How to dynamically $set a subdocument field in mongodb? [duplicate]
Asked Answered
C

1

13

I've run into a situation where I need to dynamically update the value of a field in a subdocument. The field may or may not already exist. If it doesn't exist, I'd like mongo to create it.

Here's an example document that would be found in my Teams collection, which is used to store members of any given team:

{
  _id : ObjectId('JKS78678923SDFD678'),
  name : "Bob Lawblaw",
  status : "admin",
  options : {
    one : "One",
    two : "Two"
  }
}

And here's the query I'm using (I'm using mongojs as my mongo client) to try and update (or create) a value in the options subdocument:

var projectID = 'JKS78678923SDFD678';
var key = 'Three';
var value = 'Three';

Teams.findAndModify({
    query: {
        projectID:mongojs.ObjectId(projectID)
    },
    update: {
        $set : { options[key] : value }
    },
    upsert: true,
    multi: false,
    new: true
},
function(error, result, lastErrorObject){

    console.log(result);

});

But I can't get it to 'upsert' the value.

I also found this similar question, but that method didn't work either: Nodejs Mongo insert into subdocument - dynamic fieldname

Thanks in advance for any help.

Cicala answered 27/7, 2014 at 21:53 Comment(3)
No, this is not a duplicate. Same problem, different solution. Did you even read the post? Stupid janitors.Cicala
No need to be rude. How is the solution fundamentally different? It's the same approach of programmatically building up a $set object.Pearson
Because it doesn't work. The solution illustrated in the other, different problem throws an error. Which I noted in the original question. When I moved the $set operator out of the placeholder object I ended up with the desired solution, which worked. And, yes, there is a need to be plainspoken around here. There's too many people jumping at the chance to score sweet, sweet loser points by donating their janitorial services when they should really be spending their time carefully reading the questions.Cicala
C
13

Figured this out.

Essentially, you need to construct a 'placeholder' object of the sub-document you're trying to update before running the query, like so:

var projectID = 'JKS78678923SDFD678';

var key = 'Three';
var value = 'Three';

var placeholder = {};
placeholder['options.' + key] = value;

Teams.findAndModify({
    query: {
        projectID:mongojs.ObjectId(projectID)
    },
    update: {
        $set : placeholder
    },
    upsert: true,
    multi: false,
    new: true
},
function(error, result, lastErrorObject){

    console.log(result);

});

This updates any fields that already exist, and creates the field/value pair if it didn't already exist.

Cicala answered 27/7, 2014 at 22:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.