Giter VIP home page Giter VIP logo

Comments (5)

sokil avatar sokil commented on August 29, 2024 1

Hello.

ODM tries to map mongo's document to object. Any field of document in collection mapped to property of Sokil\Mongo\Document object, any embedded document mapped to Document property, also as field of embedded document.

If you do not configure your Document class to map embedded document to some Structure, it will be just array.

But you can do some tricks to get embedded document like object: https://github.com/sokil/php-mongo#embedded-documents, so in this way your Document became aggregate of another embedded documents.

In first example, when you query collection using $collection->findAsArray() with whereElemMatch, you get whole aggregate with all embedded documents inside, but only if this whole aggregat contain some fields in it's embedded documentys. Because you filtered by _id and embedded classes containing other id.

In second example, when you call native findOne, you pass second projection parameter:
https://docs.mongodb.com/v3.2/reference/method/db.collection.findOne/.

<?php
$result = $collection->getMongoCollection("Project")->findOne(
    // query
    array(
        "_id" => new MongoId("59f889e46803fa3713454b5d")
    ), 
    // projection
    array(
        "classes" => array(
            '$elemMatch' => array(
                "_id" => new MongoId("59f9d7776803faea30b895dd")
            )
        )
    )
);

This code find document by _id and project some fields.

Find by id with bool projection:

> db.test.findOne({"_id": ObjectId("59f889e46803fa3713454b5d")}, {classes: 1})
{
	"_id" : ObjectId("59f889e46803fa3713454b5d"),
	"classes" : [
		{
			"_id" : ObjectId("59f9d7776803faea30b895dd"),
			"className" : "OLA"
		},
		{
			"_id" : ObjectId("59f9d8ad6803fa4012b895df"),
			"className" : "HELP"
		},
		{
			"_id" : ObjectId("59f9d9086803fa4112b895de"),
			"className" : "DOC"
		},
		{
			"_id" : ObjectId("59f9d9186803fa4212b895de"),
			"className" : "INVOC"
		}
	]
}

Due to https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/#project-specific-array-elements-in-the-returned-array you can also project by some expressions:

Find by id and id of embedded document of "classes":

> db.test.find({"_id": ObjectId("59f889e46803fa3713454b5d")}, {"classes": {$elemMatch: {"_id" : ObjectId("59f9d9086803fa4112b895de")}}}).pretty()
{
	"_id" : ObjectId("59f889e46803fa3713454b5d"),
	"classes" : [
		{
			"_id" : ObjectId("59f9d9086803fa4112b895de"),
			"className" : "DOC"
		}
	]
}

Currently $elemMatch not supported. You can only $slice and project specific fields. And this feature require to beimplemented.

from php-mongo.

sokil avatar sokil commented on August 29, 2024 1

yes, this feature will be implemented. Thanks for interesting lib )

from php-mongo.

sokil avatar sokil commented on August 29, 2024 1

Implemented in v.1.22.2

Useage:

public function testElemMatch()
    {
        // create new document
        $this->collection
            ->createDocument(array(
                "_id"=> new \MongoId("59f889e46803fa3713454b5d"),
                "projectName" => "usecase-updated",
                "classes" => array(
                    array(
                        "_id" => new \MongoId("59f9d7776803faea30b895dd"),
                        "className" => "OLA"
                    ),
                    array(
                        "_id" => new \MongoId("59f9d8ad6803fa4012b895df"),
                        "className" => "HELP"
                    ),
                    array(
                        "_id" => new \MongoId("59f9d9086803fa4112b895de"),
                        "className" => "DOC"
                    ),
                    array(
                        "_id" => new \MongoId("59f9d9186803fa4212b895de"),
                        "className" => "INVOC"
                    )
                )
            ))
            ->save();
        // filter embedded documents
        $filteredClasses = $this->collection
            ->find()
            ->elemMatch(
                'classes',
                function(Expression $e) {
                    $e->where('_id', new \MongoId("59f9d9186803fa4212b895de"));
                }
            )
            ->one()
            ->classes;
        $this->assertEquals(
            'INVOC',
            $filteredClasses[0]['className']
        );
    }

from php-mongo.

fahimmahmoodmir avatar fahimmahmoodmir commented on August 29, 2024

I tried using aggregation framework and comes up with following query:

$result = $collection->aggregate(array(
    array(
        '$match' => array(
            "_id" => new MongoId("59f889e46803fa3713454b5d")
        )
    ),
    array(
        '$project' => array(
            'classes' => array(
                '$filter' => array(
                    'input' => '$classes',
                    'as' => 'classItem',
                    'cond' => array(
                        '$eq' => array('$$classItem._id' => new MongoId("59f9d7776803faea30b895dd"))
                    )
                )

            )

        )
    )

));

its giving me following exception:

Sokil\\Mongo\\Exception\nMessage: Aggregate error: Unrecognized expression '$$classItem._id'\nFile:

is there any syntax error?

from php-mongo.

fahimmahmoodmir avatar fahimmahmoodmir commented on August 29, 2024

Thank you for the detailed answer. I wanted to move toward the mapping of ODM to a class so i will try it with the mapping functionality. Moreover as you mentioned that $elemMatch is not yet implemented so this mean this post can be labeled as enhancement for the development of $elemMatch.

One more update is that I tried with aggregation query and somehow i was able to retrieve desired results. I was making a mistake in the syntax of the aggregation query. Following is my updated aggregation query for retrieving matched embedded document (i am using $filter array aggregation function):

$collection = $PHPMongoDBInstance->getCollection("Project");
$result = $collection->aggregate(array(
    array(
        '$match' => array(
            "_id" => new MongoId('59f889e46803fa3713454b5d')
        )
    ),
    array(
        '$project' => array(
            'classes' => array(
                '$filter' => array(
                    'input' => '$classes',
                    'as' => 'class',
                    'cond' => array(
                        '$eq' => array('$$class._id', new MongoId("59faff836803fa3b1203d2e5"))
                    )
                )
            ),
            'projectName' => 1
        )
    )
));

the problem was in the syntax of the following expression:
'$eq' => array('$$classItem._id' => new MongoId("59f9d7776803faea30b895dd"))

I learned that it shouldn't be a associative array rather each element in the expression should be a separate array item like this:

'$eq' => array('$$class._id', new MongoId("59faff836803fa3b1203d2e5"))

With this conclusion i am able to get the results correctly.

from php-mongo.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.