spiritworld spiritworld - 1 year ago 82
JSON Question

Mongodb: Add a field into embedded document (no array)

I'm trying to update a mongodb json document by single field. I know it would be easy if my data was in object array but beacause of reasons and uninformed early design choices it's just objects within objects.

structure of the single document in my collection:

"_id": 123123,
"drivers_teams": {
"drivers" : {
"4" : { <data> },
"5" : { <data indeed> },

I want to add new object e.g

const collection = db.get('collection');
let drivers = { };
drivers['111'] = { <new data> };

collection.update({}, {$set: { drivers_teams: { drivers } }}, { upsert: true }, function (err, doc) { ... });

But the outcome is that original objects in "drivers_teams" are wiped out and has only the new field in it.

If I try:

collection.update({}, {$set: { drivers }}, { upsert: true }, function (err, doc) { ... });

It non surprisingly inserts a new field "drivers" outside the drivers_teams

"_id": 123123,
"drivers" : { <new data> },
"drivers_teams": { <still original> }

Similar problem (+solution) here but json isn't nested like mine.

Is there a way to even accomplish what I'm trying to do? Or should I just give up and overwrite the whole document when I want to update a single field?


Working solution here is
{$set: { 'drivers_teams.drivers.111': <data> }}
but what I should have mentioned is that example key '111' is actually unknown, it comes from client when it sends update data. That's why the new object was created by this solution: dynamically name mongo key field

Writing anything like
{ 'drivers_teams.driver.' + key: <data> }
throws error.

Answer Source

It is given in the documentation of '$set' that to specify a field in an embedded document or in an array, you can use the dot notation. For your case you can do:

      $set: { "drivers_teams.drivers.111": { <new data> }}
   { upsert: true }, function (err, doc) { ... });


Edit: If you are generating the field name dynamically, you can do:

const collection = db.get('collection');
let set_obj= { };  
set_obj['drivers_teams.driver.' + key] =  { <new data> };

collection.update({}, {$set: set_obj }})