8

im new with mongo and so far have no issue using it. Until i stuck at this. I need to push a document to an array inside an array. Can refer to json below.

{
    'user_id':'{1231mjnD-32JIjn-3213}',
    'name':'John',
    'campaigns':
        [
            {
                'campaign_id':3221,
                'start_date':'12-01-2012',
                'messages':
                    [
                        {
                            'message_id':211134,
                            'email':'john@gmail.com'
                        }
                    ]
            },
            {
                'campaign_id':3222,
                'start_date':'13-01-2012',
                'messages':
                    [
                        {
                            'message_id':315521,
                            'email':'john@gmail.com'
                        }
                    ]
            }
        ]
}

I want to push one document to an array of messages in a campaigns array(regardless ordering). Meaning that, i need to append new document to an array of messages. And all those messages is from inside another array or campaigns per user. Im using python so my code will be like this.

query = {"user_id" : "{1231mjnD-32JIjn-3213}", "campaigns.campaign_id": 3221}
message = {"message_id":4213122, "email":"john@gmail.com"}
op = {"$push" : {"campaigns.messages":message}}
mongo.TestDatabase.members.update(query, op)

There is no error upon execution. But the document seems to have no changes(no update made). What am i doing wrong here?

Andrew Orsich
  • 52,935
  • 16
  • 139
  • 134
khairul.ikhwan
  • 527
  • 1
  • 5
  • 13

2 Answers2

9

Having arrays inside arrays is almost always a bad idea for a number of reasons. I'd put the campaigns in a dedicated collection so they become top level documents.

That said, you can push to a message array of a specific campaign through :

db.members.update(
    {"user_id" : "{1231mjnD-32JIjn-3213}", "campaigns.campaign_id": 3221},
    {$push:{"campaigns.$.messages":{"message_id":4213122, "email":"john@gmail.com"}}}
)
Remon van Vliet
  • 18,365
  • 3
  • 52
  • 57
  • Thanks for the solution. It did work. Yes, i agree with you, array inside array is a bad idea. I can see it from my code now. Its a bit messy. :( – khairul.ikhwan Feb 09 '12 at 14:23
  • 2
    Yes, and more importantly you can never edit messages without overwriting the entire array as you are not allowed to use multiple positional operators ($). Fix for this here https://jira.mongodb.org/browse/SERVER-831 – Remon van Vliet Feb 09 '12 at 14:38
  • Ahh, this is what im searching for just now. Im looking is there any way to use multiple positional operators. So its confirm that we cannot use it. Also, i get this exception : exception: can't append to array using string field name [$] code:13048 503ms. Thanks a lot. :) – khairul.ikhwan Feb 09 '12 at 16:19
  • @RemonvanVliet in this case the item is being pushed to an array. So does it require a positional operator `$`? – Azima Mar 24 '23 at 00:50
0

if you got into error mongodb The positional operator did not find the match needed from the query. then you need to use $elemMatch to select the parent array first.

await Booking.findOneAndUpdate(
              {
                _id: data.id,
                products: {
                  $elemMatch: {
                    id: product.id,
                  },
                },
              },
              {
                $push: {
                  'products.$.slots': {
                    $each: product.slots.map((slot) => {
                      return { id: slot.id, discount: slot.discount };
                    }),
                  },
                },
              },
              { new: true }
            );
          
Rafiq
  • 8,987
  • 4
  • 35
  • 35