1

This sounds like it would be similar to a Mongo $set. In this case, I would like to update the document (update and/or delete fields) but ignore the field creatorName, keeping it the same.

Example document:

{id: 1, firstName: 'Testy', middleName: 'Jim', lastName: 'Shorts', creatorName: 'User1'}

Updated to:

{id: 1, firstName: 'Production', lastName: 'Pants', creatorName: 'User1'}

If I use set, creatorName remains the same (good) and firstName and lastName are updated (good), but middleName is not deleted (bad). Set limits the ability to remove a field during an update.

Can this be done in a query? Without $unset?

Chandrew
  • 16,987
  • 4
  • 24
  • 40
  • Sure - you can use $set and $unset in the same query - http://stackoverflow.com/questions/17760741/how-to-use-unset-and-set-in-combination-in-mongodb – Lix Aug 20 '14 at 15:34
  • Good to know, except in some cases, I would not know which fields to $unset. All I would know is how the new document looks like, and I need to ignore certain fields. It's possible to lookup the previous document, and compare, but costs performance. – Chandrew Aug 20 '14 at 15:39
  • Yes - It sounds like you are trying to do quite a complex operation that mongo doesn't support directly. – Lix Aug 20 '14 at 15:40

2 Answers2

1

It sounds like there might be more complicated stuff going on, but you've only hinted at it in the comments so I can't really speak to it. There is, however, a good way to do what you want with the name situation. Store the name fields as an embedded object and update the object:

> db.characters.findOne()
{
    "_id" : ObjectId("53f6293de062d5cdbec6553e"),
    "creatorName" : "Stan Smalls",
    "name" : {
        "first" : "Jack",
        "middle" : "B",
        "last" : "Quick"
    }
}
> db.characters.update({ "_id" : ObjectId("53f6293de062d5cdbec6553e") },
    { "$set" : {
        "name" : {
            "first" : "Sam",
            "last" : "Slow"
            }
        }
    }) 
> db.characters.findOne()
{
    "_id" : ObjectId("53f6293de062d5cdbec6553e"),
    "creatorName" : "Stan Smalls",
    "name" : {
        "first" : "Sam",
        "last" : "Slow"
    }
}

The larger principle you might be able to apply to your more complicated case is to group together fields that need to be updated with those that need to be removed whenever the related fields are updated inside an embedded document, so you can re-$set the document and effectively update some fields while default removing some fields and preserving others.

wdberkeley
  • 11,531
  • 1
  • 28
  • 23
  • Hey, that's a really good answer for this problem and clever way to handle it. Unfortunately, I can't implement it at this moment because I have so many documents already and other parts of code rely on my current format. A rewrite would take too long. Would definitely be useful if I could design from scratch. – Chandrew Aug 21 '14 at 20:42
0
const a = {
    id: 1,
    firstName: 'Testy',
    middleName: 'Jim',
    lastName: 'Shorts',
    creatorName: 'User1'
}

const b = {
    id: 1,
    firstName: 'Production',
    lastName: 'Pants',
    creatorName: 'User1'
}

delete b["id"];
// Maybe this..
delete b["_id"];

db.User.updateOne({id: 1}, {"$set": b});
JaeIL Ryu
  • 159
  • 10