0

I want to create a multidimensional collection. The collection has locations. Each locations has users and each user has photos.

Right now the collection has locations e.g.

{ "_id" : ObjectId( "52148266c36b4403e855bef9" ),
  "latitude" : 48.958,
  "id" : "110600715",
  "longitude" : 9.13,
  "name" : "Coffee" }

My final result need to be something like:

{ "_id" : ObjectId( "52148266c36b4403e855bef9" ),
  "latitude" : 48.958,
  "id" : "110600715",
  "longitude" : 9.13,
  "name" : "Coffee", 
  'users' : [
        {
        'user' : 45,
        'username' : 'Me',
        'user_fullname': 'Name Lastname',
        'photos': [
            {
            'photo_id' : 10,
            'created_time' : 1236456712,
            'link' : 'http...',
            'image' : 'http...',
            'tags' : 'a'
            },
            {...}
            ] # end of photos list
        },
        {...}
        ] #end of users list
}

If the user does not exist create new user and add the first picture. If the user exists add the next picture with unique photo_id.

This is a sample I tried the following. I am using pymongo with python. I know I am missing a second $addToSet or something similar.

db.col.update( {'_id':location_id['_id']},
            { '$addToSet' : 
                { 
                'user' : int(i['user']['id']),
                'username' : i['user']['username'],
                'user_fullname': i['user']['full_name'],
                'photos':
                    {
                    'photo_id' : i['id'],                                   
                    'created_time' : int(i['created_time']),
                    'link' : i['link'],
                    'image' : i['images']['url'],
                    'tags' : i['tags']
                    }
                }
            }
        )
Cœur
  • 37,241
  • 25
  • 195
  • 267
Diolor
  • 13,181
  • 30
  • 111
  • 179
  • possible duplicate of [Is it possible to utilize $addToSet multiple times in the same update?](http://stackoverflow.com/questions/16595195/is-it-possible-to-utilize-addtoset-multiple-times-in-the-same-update) – WiredPrairie Aug 21 '13 at 10:55

1 Answers1

0

You can't do this in a single operation - you can do an update and check how many it updated.

Here we are using the default write concern (from MongoClient) eg: w:1 and we first query and expect there to be the user for the location:

result = db.col.update(
            {'_id':location_id['_id'], "users": {"$elemMatch": {'user' : int(i['user']['id'])}}}, 
            {'$addToSet': {"photos": {'photo_id' : i['id'],                                   
                                  'created_time' : int(i['created_time']),
                                  'link' : i['link'],
                                  'image' : i['images']['url'],
                                  'tags' : i['tags']}}});

If the result['n'] equals 0 it means we didn't match and that there is no user i[user] for that location. So we can use $addToSet as well.

if result['n'] == 0:
   db.col.update({'_id':location_id['_id']},
        { '$addToSet' : 
            { 
            'user' : int(i['user']['id']),
            'username' : i['user']['username'],
            'user_fullname': i['user']['full_name'],
            'photos':
                [{'photo_id' : i['id'],                                   
                  'created_time' : int(i['created_time']),
                  'link' : i['link'],
                  'image' : i['images']['url'],
                  'tags' : i['tags']
                }]
            }
        });

note:

As we are doing two operations - there is a theoretical race condition which may mean that the second update doesn't update anything because some other thread has added the user to the location. If you want to ensure it does update you should double check the second update result and then possibly loop back. It depends on how real this race condition is.

Ross
  • 17,861
  • 2
  • 55
  • 73