nimeshkiranverma
nimeshkiranverma

Reputation: 1428

Conditions in Find, Mongo

I have a mongo collection with doc as follows:-

{
    "_id" : ObjectId("55a9378ee2874f0ed7b7cb7e"),
    "_uid" : 10,
    "impressions" : [
            {
                    "pos" : 6,
                    "id" : 123,
                    "service" : "furniture"
            },
            {
                    "pos" : 0,
                    "id" : 128,
                    "service" : "electronics"
            },
            {
                    "pos" : 2,
                    "id" : 127,
                    "service" : "furniture"
            },
            {
                    "pos" : 2,
                    "id" : 125,
                    "service" : "electronics"
            },
            {
                    "pos" : 10,
                    "id" : 124,
                    "service" : "electronics"
            }
    ]
},
{
    "_id" : ObjectId("55a9378ee2874f0ed7b7cb7f"),
    "_uid" : 11,
    "impressions" : [
            {
                    "pos" : 1,
                    "id" : 124,
                    "service" : "furniture"
            },
            {
                    "pos" : 10,
                    "id" : 124,
                    "service" : "electronics"
            },
            {
                    "pos" : 1,
                    "id" : 123,
                    "service" : "furniture"
            },
            {
                    "pos" : 21,
                    "id" : 122,
                    "service" : "furniture"
            },
            {
                    "pos" : 3,
                    "id" : 125,
                    "service" : "electronics"
            },
            {
                    "pos" : 10,
                    "id" : 121,
                    "service" : "electronics"
            }
    ]
}

My aim is to find all the "id" in a particular "service" say "furniture" i.e to get results like this:

[122,123,124,127]

But i'm not able to figure out how to frame the condition in

db.collection_name.find()

because of the difficulty of having condition for the 'n' th element in an array, "impressions[n]":"value".

One option is to use the "id"s obtained perform aggregate operation to find impressions for each "id" for a service as suggested by the answer to this question I asked earlier:- MapReduce in PyMongo.

But I only want the list of distinct 'id' in a service not the impressions. Kindly help!

Upvotes: 0

Views: 116

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50406

You need the aggregration framework for meaningful results. So much like this:

result = db.collection.aggregate([
    { "$match": {
        "impressions.service": "furniture"
    }},
    { "$unwind": "$impressions" },
    { "$match": {
        "impressions.service": "furniture"
    }},
    { "$group": {
        "_id": "$impressions.id"
    }}
])

Or better yet with MongoDB 2.6 or greater, which can remove the array items unmatched "prior" to $unwind with $redact:

result = db.collection.aggregate([
    { "$match": {
        "impressions.service": "furniture"
    }},
    { "$redact": {
       "$cond": {
           "if": { 
               "$eq": [
                   { "$ifNull": [ "$service", "furniture" ] },
                   "furniture"
               ]
           },
           "then": "$$DESCEND",
           "else": "$$PRUNE"
       }
    }},
    { "$unwind": "$impressions" },
    { "$group": {
        "_id": "$impressions.id"
    }}
])

Which yields:

{ "_id" : 122 }
{ "_id" : 124 }
{ "_id" : 127 }
{ "_id" : 123 }

Not a plain "list", but just transform it, therefore :

def mapper (x):
    return x["_id"]

map(mapper,result)

Or:

map(lambda x: x["_id"], result)

To give you:

[122, 124, 127, 123]

If you want it "sorted" then either add a $sort stage at the end of the aggregation pipeline or sort the resulting list in code.

Upvotes: 1

Related Questions