MFB
MFB

Reputation: 19817

What is the best data structure for embedded docs MongoDB?

Suppose each of my users can save many "smart searches":

user = {
    'username':'johncit',
    'smart_searches': [
        {'name':'last 24 hrs','terms':{'modifiedby':datetime(2012,1,1),'title':'foobar'}},
        {'name':'blabla','terms':{'title':'whatever','otherfield':500}}
            ]
        }

Now say John hits his 'blabla' search. How do I get the terms? I can get all John's smart searches like this:

db.Users.find_one({
        'username':'johncit','smart_searches':{'$elemMatch':{'Name':'blabla'}}})

But this returns the whole document, not just the terms for the 'blabla' search, which is what I really need. Do I then have to figure out the precise terms on the client-side? Or is this a case for putting 'smart_searches' in their own collection? Is there a better structure?

I would love to hear your thoughts.

Upvotes: 0

Views: 90

Answers (2)

RameshVel
RameshVel

Reputation: 65877

Positional operator will do the trick

> db.Users.find({'username':'johncit','smart_searches':{'$elemMatch':{'name':'blabla'}}},{'smart_searches.$.terms':1}).pretty()
{
    "_id" : ObjectId("5099ab303d550a068f16d5c5"),
    "smart_searches" : [
        {
            "name" : "blabla",
            "terms" : {
                "title" : "whatever",
                "otherfield" : 500
            }
        }
    ]
}

Update:

To update the terms with the positional operator, you can write

db.Users.update({'username':'johncit',
                 'smart_searches':{'$elemMatch':{'name':'blabla'}}},
                  {$set:{'smart_searches.$.terms':{title:'changed',otherfield:200}}},
                  false,true)

Upvotes: 2

JohnnyHK
JohnnyHK

Reputation: 312035

You want to use the $elemMatch projection operator instead of the query operator.

db.Users.find_one(
    {'username':'johncit', 'smart_searches.name':'blabla'},
    {'username': 1, 'smart_searches': {'$elemMatch': {'name':'blabla'}}})

You don't need to use $elemMatch in your query object because you're only matching one component: name.

Upvotes: 0

Related Questions