Question

I have the following structure within a mongoDB collection:

{
        "_id" : ObjectId("5301d337fa46346a048b4567"),
        "delivery_attempts" : {
                "0" : {
                        "live_feed_id" : 107,
                        "remaining_attempts" : 2,
                        "delivered" : false,
                        "determined_status" : null,
                        "date" : 1392628536
                }
        }
}

// > db.lead.find({}, {delivery_attempts:1}).pretty();

I'm trying to select any data from that collection where remaining_attempts are greater than 0 and a live_feed_id is equal to 107. Note that the "delivery_attempts" field is of a type hash.

I've tried using an addAnd within an elemMatch (not sure if this is the correct way to achieve this).

    $qb = $this->dm->createQueryBuilder($this->getDocumentName());

    $qb->expr()->field('delivery_attempts')
        ->elemMatch(
            $qb->expr()
                ->field('remaining_attempts')->gt(0)
                ->addAnd($qb->expr()->field('live_feed_id')->equals(107))
    );

I do appear to be getting the record detailed above. However, changing the greater than test to 3

->field('remaining_attempts')->gt(3)

still returns the record (which is incorrect). Is there a way to achieve this?


EDIT: I've updated the delivery_attempts field type from a "Hash" to a "Collection". This shows the data being stored as an array rather than an object:

    "delivery_attempts" : [
            {
                    "live_feed_id" : 107,
                    "remaining_attempts" : 2,
                    "delivered" : false,
                    "determined_status" : null,
                    "date" : 1392648433
            }
    ]

However, the original issue still applies.

Was it helpful?

Solution

You can use a dot notation to reference elements within a collection.

    $qb->field('delivery_attempts.remaining_attempts')->gt(0)
       ->field('delivery_attempts.live_feed_id')->equals(107);

OTHER TIPS

It works fine for me if I run the query on mongo.

db.testQ.find({"delivery_attempts.remaining_attempts" : {"$gt" : 0}, "delivery_attempts.live_feed_id" : 107}).pretty()

so it seems something wrong with your PHP query, I suggest running profiler to see which query is actually run against mongo

db.setProfilingLevel(2)

This will log all operation since you enable profiling. Then you can query the log to see which the actual queries

db.system.profile.find().pretty()

This might help you to find the culprit.

It sounds like your solved your first problem, which was using the Hash type mapping (instead for storing BSON objects, or associative arrays in PHP) instead of the Collection mapping (intended for real arrays); however, the query criteria in the answer you submitted still seems incorrect.

$qb->field('delivery_attempts.remaining_attempts')->gt(0)
   ->field('delivery_attempts.live_feed_id')->equals(107);

You said in your original question:

I'm trying to select any data from that collection where remaining_attempts are greater than 0 and a live_feed_id is equal to 107.

I assume you'd like that criteria to be satisfied by a single element within the delivery_attempts array. If that's correct, the criteria you specified above may match more than you expect, since delivery_attempts.remaining_attempts can refer to any element in the array, as can the live_feed_id criteria. You'll want to use $elemMatch to restrict the field criteria to a single array element.

I see you were using elemMatch() in your original question, but the syntax looked a bit odd. There should be no need to use addAnd() (i.e. an $and operator) unless you were attempting to apply two query operators to the same field name. Simply add extra field() calls to the same query expression you're using for the elemMatch() method. One example of this from ODM's test suite is QueryTest::testElemMatch(). You can also use the debug() method on the query to see the raw MongoDB query object created by ODM's query builder.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top