Re: Upsert on nested documents

2,202 views
Skip to first unread message
Message has been deleted

William Z

unread,
Aug 13, 2012, 1:57:24 PM8/13/12
to mongod...@googlegroups.com
Hi Alaa!

A couple of things to note:

1) "Upsert" is to create a new document if a document does not exist.  You can't use "upsert" to create a new subdocument.  MongoDB is doing exactly what you told it to do -- it's creating a new document with the same "fid", since the old one doesn't have a 'songs.song.url' field with the value you specified.

2) If you want to have a number of songs within the 'songs' sub-document, you should use an array of songs. 

This would make your overall schema design look something like this:

    {
        fid : 123,
        songs: [
            { url: "ABC", counter: 0 },
            { url: "DEF", counter: 0 }
        ]
    }

    {
        fid : 234,
        songs: [
            { url: "GHI", counter: 0 },
            { url: "HJK", counter: 0 }
        ]
    }


3) You want to do two things: add the new song into the 'songs' array if it does not exist, and to increment the counter if it does exist.  You'll need to do these in two different operations. 

In the first operation, you add an empty song record if no such song record already exists.  In the second operation, you increment an existing song record.

You need to make the first operation atomic, in case multiple database clients are trying to add the empty song record.  This means that you need to use the 'findAndModify()' operation.  The second operation can just use a simple '$set' update. 

Combining them, you get the following code:

SONGS = db.songs;

SONGS.findAndModify( {
        // only update if the particular song does not exist
        query: {fid:234, "songs.url": {"$ne":"DEF" } },        
        // Add an empty song record
        update: {"$push": {'songs': {"url":"DEF", "counter": 0} } }
        } );
SONGS.update( {fid:234, 'songs.url': "DEF" }, {"$inc": {'songs.$.counter':1} } );


Let me know if you have further questions.

 -William



On Wednesday, August 8, 2012 6:48:21 AM UTC-7, Alaa Qutaish wrote:

Hello, 

I have document with the following structure: 

{
   fid : 23979423
       songs : {
                 song: {
                      counter : 1
                      url : 2345678909
                 }
       }
}

I want to increment the counter using $inc if (fid and songs.song.url) matches the update condition otherwise I want to add new songs.song sub-document. 
what happens with me is when the condition fid and songs.song.url does not match, it creates a new document in this collection. something like this.

{
   fid : 23979423
       songs : {
                 song: {
                      counter : 1
                      url : 2345678909
                 }
       }
}

{
   fid : 23979423
       songs : {
                 song: {
                      counter : 1
                      url : 54542455454
                 }
       }
}

I think i am missing something here, 
Please advice, Thank you. 

William Z

unread,
Aug 20, 2012, 7:10:53 PM8/20/12
to mongod...@googlegroups.com

I'm not a Java programmer, but I sit a few feet away from one :-).  Here's an (untested) code sample:

  c.findAndModify(
        // only update if this song does not exist
        QueryBuilder.start("fid").is(234).and("songs.url").notEquals("DEF").get(),

        // add an empty song record
        new BasicDBObject("$push", new BasicDBObject("songs", new BasicDBObject("url", "DEF").append("counter", 0))
        );

   c.update(
        QueryBuilder.start("fid").is(234).and("songs.url").is("DEF").get(),

        new BasicDBObject("$inc", new BasicDBObject("songs.$.counter", 1))
        );


 -William

On Monday, August 20, 2012 12:06:13 AM UTC-7, wakeup wrote:
William, you have a java version of this code snipplet?



Op maandag 13 augustus 2012 19:57:24 UTC+2 schreef William Z het volgende:

wakeup

unread,
Aug 21, 2012, 5:32:13 AM8/21/12
to mongod...@googlegroups.com
thanx william, also to you collegue!

Op dinsdag 21 augustus 2012 01:10:53 UTC+2 schreef William Z het volgende:
Reply all
Reply to author
Forward
0 new messages