-1

I'm trying to add a new message (with key "3") to the nested "messages" document but $addToSet or $push won't work. Is it possible to push a new message element to such a structure? In the beginning the messages property was an array but my mongodb provider converts arrays into such structures. Just for your information: I'm accessing the mongodb via node.js and mongojs but a native mongodb solution would be perfect too.

{
    "messages" : 
    {
        "0" : 
        {
            "foo": "bar0"  
        },
        "1" : 
        {
            "foo": "bar1"  
        },
        "2" : 
        {
            "foo": "bar2"   
        },
    },
    "name" : "MyName"   
}
seveves
  • 1,282
  • 4
  • 17
  • 37
  • 2
    `$addToSet` and `$push` will only work with arrays (enclosed within []). In your document, `messages` is an object rather than an array. So, you'll have to use the `update` statement: `db.collection.update({}, {$set:{"messages.3":{"foo":"bar3"}}})` – Anand Jayabalan Sep 23 '14 at 15:31
  • I thought of something like that but then I have to get the count of the messages document first, right? – seveves Sep 23 '14 at 15:42
  • 2
    Which is why you should probably be using an array instead. – JohnnyHK Sep 23 '14 at 15:42
  • Indeed buuuuut when I add the document via the editor of my provider then it converts the array into such a document :/ – seveves Sep 23 '14 at 15:45
  • Hm I am using the one from MongoSoup. It is a german mongodb provider. – seveves Sep 23 '14 at 15:49
  • If you are storing as an array, might be there is an issue with the editor displaying it. You should store it as an array, as you were, and $push, $addToSet would definitely work. Show how you used them. – BatScream Sep 23 '14 at 16:28
  • var message = { "foo": "bar3" }; mongodb.collection.update({ _id:mongojs.ObjectId(objectId) }, { $push: { messages: message }}, callback); Note: this is mongojs notation – seveves Sep 23 '14 at 19:55

2 Answers2

0

The problem is that the editor of MongoSoup automatically transforms arrays into a collection of documents. When I create the array via command line or my node.js application then everything is like I've expected it.

Thank you anyway ... my bad!

seveves
  • 1,282
  • 4
  • 17
  • 37
-1

Essentially you just want to add a subdocument, so simply $setting the document will work:

db.bar.update({_id : ObjectId("542194f8b32cda36885e1d9e") }, 
              {$set : {"messages.3" : {"foo" : "bar3"}}})

You would need to substitute an appropriate match criteria rather than the _id I used of course based on what your real documents look like. Full procedure for adding/updating your sample document as follows:

> foo = {
    "messages" : {
        "0" : {
            "foo" : "bar0"
        },
        "1" : {
            "foo" : "bar1"
        },
        "2" : {
            "foo" : "bar2"
        }
    },
    "name" : "MyName"
}

> db.bar.insert(foo)
WriteResult({ "nInserted" : 1 })

> db.bar.findOne()
{
    "_id" : ObjectId("542194f8b32cda36885e1d9e"),
    "messages" : {
        "0" : {
            "foo" : "bar0"
        },
        "1" : {
            "foo" : "bar1"
        },
        "2" : {
            "foo" : "bar2"
        }
    },
    "name" : "MyName"
}

> db.bar.update({_id : ObjectId("542194f8b32cda36885e1d9e") }, {$set : {"messages.3" : {"foo" : "bar3"}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.bar.findOne()
{
    "_id" : ObjectId("542194f8b32cda36885e1d9e"),
    "messages" : {
        "0" : {
            "foo" : "bar0"
        },
        "1" : {
            "foo" : "bar1"
        },
        "2" : {
            "foo" : "bar2"
        },
        "3" : {
            "foo" : "bar3"
        }
    },
    "name" : "MyName"
}

The obvious limitation is that this would overwrite any existing messages.3 field if it already exists, so you will need to be careful and you need to keep track of the latest message in the field also.

BatScream
  • 19,260
  • 4
  • 52
  • 68
Adam Comerford
  • 21,336
  • 4
  • 65
  • 85
  • The OP does not store the document in such a way. Its stored as an array. – BatScream Sep 23 '14 at 15:49
  • That's actually not what the question says, in fact the title explicitly says that it is a nested doc and not an array, which is why the $push operator will not work – Adam Comerford Sep 23 '14 at 16:02
  • I guess then, the title is misleading, please read the description and the comments. – BatScream Sep 23 '14 at 16:04
  • "In the beginning the messages property was an array but my mongodb provider converts arrays into such structures", "Indeed buuuuut when I add the document via the editor of my provider then it converts the array into such a document :/", and the title seem to be confusing. I don't think the answer is correct in this context. – BatScream Sep 23 '14 at 16:11
  • Right, so the document is not an array, it *is* a nested document, and I have used the document example given. If what you are saying is correct, then every single part of the question is incorrect - title, description and sample document. I have answered the question as asked, you appear to want me to answer something that was never actually asked that you are inferring from.......nowhere - that makes no sense to me – Adam Comerford Sep 23 '14 at 16:15
  • I checked the database via command line and mongojs and when I do a "find" query on the messages array (supposed to be an array) then I'll get message documents and no array ... seems to me that it is really stored as a collection of documents. Maybe this is why: https://www.mongosoup.de/blog-entry/Storing-Large-Lists-In-MongoDB.html – seveves Sep 23 '14 at 19:58