0

I'm new to meteor/mongo/js as a stack and I'm getting lost in JSON arrays and referencing them. Based another SO answer ( and the docs) I think I am close...

A document in the Orders collection, the document has nested arrays.

Order -> orderLines -> lineItems:

Sample doc:

{
"_id" : "27tGpRtMWYqPpFkDN",
"orderLines" : [
    {
        "lineId" : 1,
        "name" : "Cheese & Pickle",
        "instructions" : "",
        "lineItems" : [
            {
                "name" : "Cheddar Cheese",
                "quantity" : 1
            },
            {
                "name" : "Branston Pickle",
                "quantity" : 1
            },
            {
                "name" : "Focaccia Roll",
                "quantity" : 1
            }
        ]
    }
  ]
}

What I'm trying to do from the meteor/mongo shell:

  1. Add "instructions" of "foo" to orderLines where lineId = 1
  2. Put a new item on lineItems array

This appears to hang...

meteor:PRIMARY> db.orders.update({_id:"27tGpRtMWYqPpFkDN","orderLines.lineId":"1", {$set: {"orderLines.$.instructions":"foo"}})
... 

This doesn't like the identifier in the query

meteor:PRIMARY> db.orders.update({_id:"27tGpRtMWYqPpFkDN", "orderLines.lineId":"1"}, {$push:{"orderLines.$.lineItems":" { "name" : "butter", "quantity" : 1}"}});
2015-10-27T16:09:54.489+0100 SyntaxError: Unexpected identifier
Community
  • 1
  • 1
Andy
  • 11
  • 2
  • You'll be happier if you re-factor this to remove arrays--it makes many mongo queries simpler/faster/possible. I would make a `OrderLine` collection that has the order `_id` as a field; then I'd have a `LineItem` collection that links to the `OrderLine`. While this seems more complicated now, it will make querying and potential math operations easy later. – Autumn Leonard Oct 27 '15 at 15:24
  • Thanks Autumn, I think I am going to have to do as you say, but it feels a bit _'relational'_ :) – Andy Oct 27 '15 at 17:46

2 Answers2

1

Thanks all for your comments... but I found out some answers, posted for reference

Item 1 - using $set on a value within an array

This was failing due to two typos, one missing closing } at the end of the query, second was quoting the value "1" for itemId in the query.

This works:

 db.orders.update({_id:"27tGpRtMWYqPpFkDN", orderLines.lineId":1}, 
 {$set: {"orderLines.$.instructions":"foo"}})

I also realised that when I said "It appears to hang" it is the cli waiting for a valid statement, so hints at a missing } or )!

Item 2 - using $push to add data to an array - 2 levels nested

This was failing due to quoting around the array data

db.orders.update({_id:"27tGpRtMWYqPpFkDN", "orderLines.lineId":1 }, 
{$push:{"orderLines.$.lineItems": { "name" : "butter", "quantity" : 1} }})

Nested Arrays: can use $ positional operator

What I want to do next is use $set on an item in the second level array, and this would require using the $ positional operator twice:

db.orders.update({"orderLines.lineId":1, lineItems.name:"Cheddar Cheese"},
{$set: {"orderLines.$.lineItems.$.quantity": 2}})

This throws an error:

Too many positional (i.e. '$') elements found in path

There is an open MongoDB enhancement request for this but it's been open since 2010

Andy
  • 11
  • 2
0

$push adds a new element to an array. You're merely trying to set the value of a particular key in an array element.

Try:

db.orders.update({ _id: "27tGpRtMWYqPpFkDN", "orderLines.lineId": 1},
  { $set: { "orderlines.$.instructions": "foo" }})

docs

Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • Thanks Michel, I was using $set for the first task updating "instructions"; the $push was for an array update I was doing in the second task. – Andy Oct 27 '15 at 17:45