121

I'm using the Mongoose Library for accessing MongoDB with node.js

Is there a way to remove a key from a document? i.e. not just set the value to null, but remove it?

User.findOne({}, function(err, user){
  //correctly sets the key to null... but it's still present in the document
  user.key_to_delete = null;

  // doesn't seem to have any effect
  delete user.key_to_delete;

  user.save();
});
Daniel Beardsley
  • 18,289
  • 20
  • 62
  • 76
  • 1
    I thought I had found it, but after some tests: probably not. This has some good discussion on the topic though. http://groups.google.com/group/mongoose-orm/browse_thread/thread/6053e3b8d4fe9098 – Stephen Aug 15 '11 at 15:28
  • LOL nevermind, I guess this was your post! – Stephen Aug 15 '11 at 15:31

10 Answers10

194

In early versions, you would have needed to drop down the node-mongodb-native driver. Each model has a collection object that contains all the methods that node-mongodb-native offers. So you can do the action in question by this:

User.collection.update({_id: user._id}, {$unset: {field: 1 }});

Since version 2.0 you can do:

User.update({_id: user._id}, {$unset: {field: 1 }}, callback);

And since version 2.4, if you have an instance of a model already you can do:

doc.field = undefined;
doc.save(callback);
staackuser2
  • 11,242
  • 4
  • 40
  • 40
  • This has been fixed in Mongoose 2.X, so you can leave the collection out. – staackuser2 Nov 13 '11 at 22:30
  • What's the fix? How does one do it. I've read the docs I have. – grantwparks Apr 02 '12 at 00:31
  • 4
    Either use `User.update({ _id: id }, { $unset: { field: 1 }}, callback)` or if you have a document instance, set the path to undefined and then save it: `doc.field = undefined; doc.save()` – aaronheckmann Aug 21 '12 at 21:31
  • 27
    Just a note that if you're trying to remove an old property that's no longer defined in your schema you need to do `doc.set('field', undefined)` – evilcelery Oct 09 '13 at 11:07
  • 3
    what about deleting `doc.field.foo` ? – chovy Jul 15 '14 at 04:28
  • Will it work if this key is an object? I.e embedded doc, or am i need to set each property of this object to undefined individualy? – Max Yari Apr 01 '15 at 14:43
  • @chovy delete has no effect in v 4.0.2. I guess it makes sense that you wouldn't be allowed to remove properties from a model but seems like it should just have the same effect as setting to undefined. – regularmike Jun 17 '15 at 16:03
  • 30
    @evilcelery `doc.set('field', undefined)` might not be enough since strict mode (default) does not allow to set fields which are not in the schema anymore. `doc.set('field', undefined, { strict: false })` worked fine. – Alexander Link Jul 02 '15 at 15:01
  • @AlexanderLink I tried `strict: false` as you posted, Keystone recorded that the update was performed but the field is still there... – mgol Nov 23 '15 at 13:02
  • @AlexanderLink where are you doing the doc.set? Thanks. – chemitaxis Apr 19 '17 at 09:08
  • Thank you @AlexanderLink I've spent 2 hours looking for this. you are a hero! – Eneko de la Torre Apr 29 '19 at 09:04
60

You'll want to do this:

User.findOne({}, function(err, user){
  user.key_to_delete = undefined;
  user.save();
});
deedubs
  • 631
  • 5
  • 2
35

I use mongoose and using any of the above functions did me the requirement. The function compiles error free but the field would still remain.

user.set('key_to_delete', undefined, {strict: false} );

did the trick for me.

Noushad
  • 3,506
  • 2
  • 20
  • 26
  • Upvoting this useful answer, too bad @alexander-link didn't make it an answer back in 2015 (http://stackoverflow.com/questions/4486926/delete-a-key-from-a-mongodb-document-using-mongoose#comment50381329_6938733) – w00t Oct 10 '16 at 13:36
  • 1
    Thank you for your answer, for me, the other solutions did not work for objects nested in arrays! – BenSower Oct 09 '18 at 16:08
  • @BenSower This was my case, too. Only this solution worked well because I had to delete a field with array after finding a specific document's id – Luis Febro Oct 18 '19 at 23:55
  • Note that the string is a path to the key. So, if the object you want to delete is nested, you must path to it. This answer solved my problem! – Bradyo Apr 21 '20 at 19:56
8

At mongo syntax to delete some key you need do following:

{ $unset : { field : 1} }

Seems at Mongoose the same.

Edit

Check this example.

Andrew Orsich
  • 49,434
  • 15
  • 132
  • 132
  • Can you clarify this answer and give a code example that relates to the example code above? – Daniel Beardsley Jan 04 '11 at 22:55
  • sorry but i am not expereinced at mongoose. Above syntax it's mongo syntax, so i suppose that driver for any language support this. I found some example, check it in my answer. – Andrew Orsich Jan 04 '11 at 23:34
1

Mongoose document is NOT a plain javascript object and that's why you can't use delete operator.(Or unset from 'lodash' library).

Your options are to set doc.path = null || undefined or to use Document.toObject() method to turn mongoose doc to plain object and from there use it as usual. Read more in mongoose api-ref: http://mongoosejs.com/docs/api.html#document_Document-toObject

Example would look something like this:

User.findById(id, function(err, user) {
    if (err) return next(err);
    let userObject = user.toObject();
    // userObject is plain object
});
petarr
  • 36
  • 4
1

Could this be a side problem like using

function (user)

instead of

function(err, user)

for the find's callback ? Just trying to help with this as I already had the case.

Luc
  • 15,030
  • 32
  • 113
  • 175
1

Try:

User.findOne({}, function(err, user){
  // user.key_to_delete = null; X
  `user.key_to_delete = undefined;`

  delete user.key_to_delete;

  user.save();
});
Shree
  • 18,997
  • 28
  • 86
  • 133
0

the problem with all of these answers is that they work for one field. for example let's say i want delete all fields from my Document if they were an empty string "". First you should check if field is empty string put it to $unset :

function unsetEmptyFields(updateData) {
  const $unset = {};
  Object.keys(updatedData).forEach((key) => {
    if (!updatedData[key]) {
      $unset[key] = 1;
      delete updatedData[key];
    }
  });
  updatedData.$unset = $unset;

  if (isEmpty(updatedData.$unset)) { delete updatedData.$unset; }

  return updatedData;
}

function updateUserModel(data){
const updatedData = UnsetEmptyFiled(data);

    const Id = "";
    User.findOneAndUpdate(
      { _id: Id },
      updatedData, { new: true },
    );
}

Milad ranjbar
  • 353
  • 4
  • 16
0

if you want to remove a key from collection try this method.

 db.getCollection('myDatabaseTestCollectionName').update({"FieldToDelete": {$exists: true}}, {$unset:{"FieldToDelete":1}}, false, true);
ZachB
  • 9,402
  • 2
  • 43
  • 76
Bivin Vinod
  • 1,445
  • 1
  • 10
  • 15
-5

you can use delete user._doc.key