How to update object with nested objects - Ottoman ODM?

I have complex model (model with reference). But when I get this model from the request and want to update it I would like to not to list all the fields to be updated. Say my model is:

var CustomFieldType = ottoman.model('CustomFieldType', {
    _id: {type:'string', auto:'uuid', readonly:true},
    title: {type: 'string'},
    codeName: {type: 'string'},
    baseFieldType: { ref: 'BaseFieldType'},
    customData: {type: 'Mixed'}
});

So when I want to update this object from request body I would like to do something like that:

CustomFieldType.getById(id, function (err, obj) {
     if (obj){
          obj.save(request.body, function){} ...
     }
});

All the samples I saw suggest to assign fields one by one like:

obj.name = request.body.name; //etc`

I don’t like this approach.
But I didn’t find anything like that in Ottoman. Mongoose allows you to just pass the request body like in example above. How to do it with Ottoman?
If there is no way to avoid field-by-field approach, how to update the whole object if referenced object has been changed? If I just change the key and value of this nested object I have the error “The Key of the object has changed!”
Thanks

People, please help! Please tell me that Ottoman can do it else it just pOc.

Hey Kath,

Ottoman is not currently able to perform bulk updates with a one-lined as per you’re example. A model instance is just a normal object though, so you should be free to do any kind of updates you would like before saving the model. Note that Couchbase Server only recently began supporting sub-document updates in recent releases.

Cheers, Brett

Hi Brett,
thanks for your response. I’m sorry I don’t understand what you are saying. I’m developing nodejs app, the web page sends the object back, and it’s not ModelInstance as well as its subdocuments. As soon as I’m trying to save it into database I have an error, like “it’s not ModelInstance”. How is it supposed to update the object at all, even if it doesn’t have any subdocuments? And in the case if it has it’s turned out to be a nightmare because I have to go through all the fields, see if they are referenced subdocs and create a new ModelInstance else nothing works.

Maybe I don’t understand something I don’t know. My question is not about how to save subdocument only, it’s about how to save the document at all, and particularly if it has subdocuments.

So the first question is - if I have “just object” how to update it?

Thanks!!

Hello - I ran into a similar situation and wanted to post the solution I came up with and get feedback on potential pitfalls.

Essentially I wanted to be able to update a document based on the data sent over in the request without needing to iterate through each known property setting them one by one. This approach below seems to also satisfy the need of doing partial update by only sending fields that need to change. This approach is also only needed if you have Refs defined in your models. If the model consists of basic fields/groups you can simply call model.$.schema.applyDataToObject(model, data) directly and it works as well.

Any issues that I might run into with the code below? So far in my testing it seems to work as I’d expect. The only thing I’m not happy about is the string comparison for the ModelRef type, however, I couldn’t find a way to use instanceof when I can’t load the Schema module directly.

-Tom

Function defintion:

function applyDataToModel(model, data) {
  const subModels = []

  model.$.schema.fields.forEach(i => {
    if (i.type.inspect().indexOf('ModelRef') === 0 && data[i.name]) {
      applyDataToModel(model[i.name], data[i.name])
      subModels.push(i.name)
    }
  })

  subModels.forEach(i => delete data[i])

  model.$.schema.applyDataToObject(model, data)
}

Sample Call from Express route

router.post('/:id', function (req, res, next) {
  if (req.module) {
    try {
      applyDataToModel(req.module, req.body.item)
      req.module.save(saveComplete)
    } catch (e) {
      console.log(e)
      res.status(500)
          .send(e.toString())
    }

    function saveComplete(err) {
      if (err) {
        res.status(400)
          .send(err.toString())
      } else {
        res.status(200)
          .json(req.module)
      }
    }
  }
})