8

node js,sails js,waterline. I need to update(or push) values into the below schema after insert

I am using sailsjs with waterline and mongodb.

{
"countries": {
"states": [
{
"statename": "state",
"districts": [
{
"distname": "district",
"cities": [
{
"cityname": "Hyderabad",
"places": [
                {
                  "placename": "hitechcity"
                }
              ]

          }
        ]
      }
    ]
  }
]
}
}

I need to know how to update it i need something like this after update

{
"countries": {
"states": [
{
"statename": "state",
"districts": [
{
"distname": "district",
"cities": [
{
"cityname": "Hyderabad",

              "places": [
                {
                  "placename": "hitechcity"
                },
                {
                  "placename": "someother place"
                }
              ]

          }
        ]
      }
    ]
  }
]
}
}

please someone help me.

Travis Webb
  • 14,688
  • 7
  • 55
  • 109
Shiva Gouraram
  • 147
  • 1
  • 7
  • Mogodb's '$'-operator supports only 1 level of array nesting, so I don't think there is a solution available for your current schema. perhaps you should rethink it once more and make it less nested. – Vitaly Muminov Aug 10 '13 at 10:48

2 Answers2

16

Great question! You'll want to use addToCollection():

await User.addToCollection(23, 'roles')
.members([3, 5, 6]);

Done on my phone so sorry about any typos :)

Edited Aug 7, 2018 to reflect best practices in Sails v1. More info: https://sailsjs.com/documentation/reference/waterline-orm/models/add-to-collection

mikermcneil
  • 11,141
  • 5
  • 43
  • 70
  • Thanks mikermcneil,That's great but what does that 23 means? – Shiva Gouraram Aug 11 '13 at 07:19
  • Ah, sorry- should have clarified. 23 is the id of the user we're looking for, just an example. – mikermcneil Aug 11 '13 at 21:47
  • 1
    I have the same issue and I used the solution that @mikermcneil suggests. However, I ran into trouble with race conditions. Example: The query is performed two times in a row. Both findOne-functions find the same object, and both manipulate and save the _original_ object thereby only storing the object that was changed _last_... – anissen Sep 25 '13 at 13:46
  • 2
    What if I have a large number of writes? given the fact that all this is async, there may be multiplt queries to add things to as array and all of them would find the object before changing and saving. In that case all the changes except the last one would be lost. There has got to be a quiery like {user.roles : {push : {whatever} } – Naman Goel Jan 31 '14 at 09:36
  • @NamanGoel this is a problem with noSQL/embedded-JSON databases in general. I'm no mongo expert, but I believe they achieve it by giving you a utility function. We're reticent to include too much syntactic sugar for embedded records in Waterline currently, because we'd have to standardize it and make it work across the board, which takes resources we're better off spending on support for normalized associations. You can use [`User.native()`](https://github.com/balderdashy/sails-docs/blob/master/reference/ModelMethods.md#native) to get a hold of the raw mongo cursor. Hope that helps! – mikermcneil Feb 01 '14 at 16:04
  • 1
    @anissen righto- you'd have the same problem you would doing this with Mongo out of the box-- a lack of transactions. [Here's](http://cookbook.mongodb.org/patterns/perform-two-phase-commits/) Mongo's official stance on handling transactions w/ 2-phase commits. Longer term, this will find its way into Waterline in a cross-adapter way at some point down the road. The first version of the ORM had cross-adapter transaction support, but it was removed to keep things maintainable (you can find it waaaaay back in the history of the Sails repo if you're interested) – mikermcneil Feb 01 '14 at 16:06
  • 1
    @mikermcneil User.native() would probably work fine! Thanks! I didn't know this existed. – Naman Goel Feb 10 '14 at 01:10
  • @NamanGoel also check out https://github.com/sails101/mongo-native-queries for an example app that uses `.native()` – mikermcneil Jul 01 '14 at 12:27
  • 1
    What if these `push`ed values have to be unique? Does anyone know if arrays can support `unique: true`? – Cody Jul 04 '15 at 16:48
  • 1
    @Cody That's right, they cannot-- to do that you'll want to use .native() (see the answer from @Zardoz). Alternatively you could tweak your data model and go w/ the relational approach (this is fine, even w/ mongo)-- and use associations or a "through" model. Good luck! – mikermcneil Jul 23 '15 at 13:31
  • 1
    @mikermcneil, Thanks a bunch for the helpful advice! – Cody Jul 23 '15 at 17:32
4

I found that with Sails I could not use mikermcneil answer. I had to go native:

Runtestunit.native(function(err, runtestunit){
     runtestunit.find({sessionID : sessionData.id_}).toArray(function(err, results) {
         if (err) return res.serverError(err);
         runtestunit.update({ _id: results[0]._id },
           { $push: { screenshots: filename } },
           function(err, screenshots) {
           if(err) sails.log.err( err)
         else sails.log.info("Item pushed")
       })
    });
});

FYI I'm querying my data by a sessionData.id_ key

Zardoz
  • 332
  • 2
  • 7
  • 4
    Thanks for posting this! Would you mind expanding this to explain why you needed to use `.native()` to help out folks finding this answer on Google? – mikermcneil Jul 23 '15 at 13:28