Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sub-Objects in class not populated when using projection (QXMONGODB) #127

Open
Aditya-Tolikar opened this issue May 8, 2024 · 5 comments

Comments

@Aditya-Tolikar
Copy link

When passing the columns argument in qx::dao::fetch_all, if the "column" pertains to a class variable (separately registered), its inner variables are not filled.

Illustration:

collection_1.h

#ifndef COLLECTION_1_H
#define COLLECTION_1_H

#include "common.h"

class TEST_DLL_EXP InnerObjT1
{
public:
	QString m_someStuff;

	InnerObjT1(){}
	virtual ~InnerObjT1(){}
};
typedef QSharedPointer<InnerObjT1> ptrInnerObjT1;
typedef QList<ptrInnerObjT1> listInnerObjT1;

TEST_HPP_NOBASE_REG(InnerObjT1)

class TEST_DLL_EXP collection_1
{
public:
	QString m_id;

	InnerObjT1 m_a;
	ptrInnerObjT1 m_b;
	listInnerObjT1 m_c;

	collection_1(){}
	virtual ~collection_1(){}
};

TEST_PRIMARY_KEY_QSTRING(collection_1)
TEST_HPP_NOBASE_REG(collection_1)

#endif // COLLECTION_1_H

collection_1.cpp

#include "collection_1.h"

TEST_CPP_REG (InnerObjT1)
namespace qx
{
	template<> void register_class (QxClass<InnerObjT1> &t)
	{
		t.data (&InnerObjT1::m_someStuff, "someStuff");
	}
}

TEST_CPP_REG (collection_1)
namespace qx
{
	template<> void register_class (QxClass<collection_1> &t)
	{
		t.id (&collection_1::m_id, "_id");
		t.data (&collection_1::m_a, "a");
		t.data (&collection_1::m_b, "b");
		t.data (&collection_1::m_c, "c");
	}
}

main.cpp

#include "collection_1.h"
#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);

	qx::QxClassX::registerAllClasses();

	qx::QxSqlDatabase * db = qx::QxSqlDatabase::getSingleton();
	db->setDriverName("QXMONGODB");
	db->setDatabaseName("checker3_pjection");
	db->setHostName("localhost");
	db->setPort(27017);

	QSqlError err;

	{
		/// Inserting test data
		err = qx::dao::delete_all<collection_1>();
		qDebug () << "Delete all: " << err;

		collection_1 insingObj;
		insingObj.m_a.m_someStuff = "ssa_1";
		insingObj.m_b = ptrInnerObjT1::create();
		insingObj.m_b->m_someStuff = "ssb_1";
		for (int i = 1; i < 4; i++)
		{
			ptrInnerObjT1 ot1 = ptrInnerObjT1::create();
			ot1->m_someStuff = "ssc_" + QString::number(i);
			insingObj.m_c.append(ot1);
		}

		err = qx::dao::insert(insingObj);
		qDebug () << "Inserting ... Error? : " << err;
	}


	/// Without projection
	QList<collection_1> recvObj1;
	err = qx::dao::fetch_all(recvObj1);
	qDebug ().noquote() << qx::serialization::json::to_string(recvObj1);

	/// With projection
	QList<collection_1> recvObj2;
	err = qx::dao::fetch_all(recvObj2, NULL, QStringList{} << "a" << "b" << "c");
	qDebug ().noquote() << qx::serialization::json::to_string(recvObj2);

	return 0;
}

The result I get is:

Delete all:  QSqlError("", "", "")

[QxOrm] sql query (total: 0.352 ms, db_exec: 0.226 ms) : MongoDB insert one 'collection_1' :
{
    "a": {
        "someStuff": "ssa_1"
    },
    "b": {
        "someStuff": "ssb_1"
    },
    "c": [
        {
            "someStuff": "ssc_1"
        },
        {
            "someStuff": "ssc_2"
        },
        {
            "someStuff": "ssc_3"
        }
    ]
}

Inserting ... Error? :  QSqlError("", "", "")


[QxOrm] sql query (total: 0.314 ms, db_exec: 0.305 ms) : MongoDB find many 'collection_1' :


[
    {
        "_id": "qx_oid:663b23d9ff912c570a093b91",
        "a": {
            "someStuff": "ssa_1"
        },
        "b": {
            "someStuff": "ssb_1"
        },
        "c": [
            {
                "someStuff": "ssc_1"
            },
            {
                "someStuff": "ssc_2"
            },
            {
                "someStuff": "ssc_3"
            }
        ]
    }
]

[QxOrm] sql query (total: 0.261 ms, db_exec: 0.255 ms) : MongoDB find many 'collection_1' :

{ "projection": { "a": 1, "b": 1, "c": 1 } }
[
    {
        "_id": "qx_oid:663b23d9ff912c570a093b91",
        "a": {
            "someStuff": ""
        },
        "b": {
            "someStuff": ""
        },
        "c": [
            {
                "someStuff": ""
            },
            {
                "someStuff": ""
            },
            {
                "someStuff": ""
            }
        ]
    }
]

As you see, the keys, "someStuff" inside "a", "b" and "c" were not filled in case projection was used, but were normally filled when it was not used.

@Aditya-Tolikar
Copy link
Author

If, on the other hand, I change all data types with QVariant, then the inner keys get populated.

Change in collection_1.h

class TEST_DLL_EXP collection_1
{
public:
	QString m_id;

	QVariant m_a;
	QVariant m_b;
	QVariant m_c;

	collection_1(){}
	virtual ~collection_1(){}
};

In this case, using fetch_all with the previous data in the db, I get:

[QxOrm] sql query (total: 0.263 ms, db_exec: 0.254 ms) : MongoDB find many 'collection_1' :

{ "projection": { "a": 1, "b": 1, "c": 1 } }
[
    {
        "_id": "qx_oid:663b23d9ff912c570a093b91",
        "a": {
            "someStuff": "ssa_1"
        },
        "b": {
            "someStuff": "ssb_1"
        },
        "c": [
            {
                "someStuff": "ssc_1"
            },
            {
                "someStuff": "ssc_2"
            },
            {
                "someStuff": "ssc_3"
            }
        ]
    }
]

@Aditya-Tolikar
Copy link
Author

Similarly, if I use qx::dao::call_query (...) to get the data and call qx::serialization:: functions to populate the class, it works again.

@QxOrm
Copy link
Owner

QxOrm commented May 13, 2024

Hello,

I think the issue is here :

namespace qx
{
	template<> void register_class (QxClass<collection_1> &t)
	{
		t.id (&collection_1::m_id, "_id");
		t.data (&collection_1::m_a, "a");
		t.data (&collection_1::m_b, "b");
		t.data (&collection_1::m_c, "c");
	}
}

For m_a, m_b, and m_c, you should register them as relationships.

@Aditya-Tolikar
Copy link
Author

Aditya-Tolikar commented May 13, 2024

mongosh command for reference:

db.collection_1.find()

Result:

{
  "_id": ObjectId("663b23d9ff912c570a093b91"),
  "a": {
    "someStuff": "ssa_1"
  },
  "b": {
    "someStuff": "ssb_1"
  },
  "c": [
    {
      "someStuff": "ssc_1"
    },
    {
      "someStuff": "ssc_2"
    },
    {
      "someStuff": "ssc_3"
    }
  ]
}

As you see, I only used a simple find query and the data is all stored in a single collection (~table).

Also, I haven't used fetch_all_by_relation, so the data actually does not contain any relation, which should also be visible from the /// Inserting test data part of the example .

MongoDB can store objects inside objects, contrary to SQL DBs, which is probably why this is being different.

Also, as I stated, this works when I don't add the "projection" (columns argument). If I use a relation, won't it just try to look for data in another collection which is not in the database?

@QxOrm
Copy link
Owner

QxOrm commented May 14, 2024

Hello,

You should try to create a persistable custom type : if you do that, you don't need to use relationship to link to other classes.
This is explained in the documentation here : https://www.qxorm.com/qxorm_en/manual.html#manual_460

The most important is this implementation :

namespace qx {
namespace cvt {
namespace detail {

template <> struct QxConvert_ToVariant< ExtObject3D > {
static inline QVariant toVariant(const ExtObject3D & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
{
   /* Here I convert from ExtObject3D to QVariant */
}};

template <> struct QxConvert_FromVariant< ExtObject3D > {
static inline qx_bool fromVariant(const QVariant & v, ExtObject3D & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
{
   /* Here I convert from QVariant to ExtObject3D */;
   return qx_bool(true);
}};

} // namespace detail
} // namespace cvt
} // namespace qx

Just replace ExtObject3D by your types : InnerObjT1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants