Mongoose: Trying to delete/set null a field with findOneAndUpdate

Created on 16 Sep 2016  Â·  14Comments  Â·  Source: Automattic/mongoose

I'm trying to delete (also setting it to null would be acceptable as a backup plan) the field "board" from a document that looks like this:

var cardSchema = new Schema({
  title: {
    type: String,
    required: true
  },
version: {
    type: Number,
    required: true,
    "default": 0
  },
  board: {
    type: ObjectId,
    ref: 'Board'
  },
},{strict: false});
mongoose.model('Card', cardSchema);

For my scenario, I need to use the function findOneAndUpdate in the following way:

var cardChanges = {board: undefined, version: 10};
Card
  .findOneAndUpdate({_id: "my_id"}, cardChanges, 
      {"new": true, upsert: false, passRawResult: false, 
        "overwrite": false, runValidators: true, 
         setDefaultsOnInsert: true})
  .exec(function(err, result) {
    if(err) {
      // error handlers
    }
    if(!result) {
      // No card to be updated
    }
    // ok
  });

Before the update I have the document:

{
_id: "my_id",
title: "This is my card",
board: "my_board",
version: 9
}

And after:

{
_id: "my_id",
title: "This is my card",
board: "my_board",
version: 10
}

I tried to set the board with both null and undefined, the result is the same.
For my use case I can't use the save method.
Mongoose 4.5.5, MongoDB 3.2.9
Any idea or workaround?

Thanks

can't reproduce

Most helpful comment

var cardChanges = { $set: { version: 10 }, $unset: { board: 1 } } try that as a workaround

All 14 comments

var cardChanges = { $set: { version: 10 }, $unset: { board: 1 } } try that as a workaround

Thanks @vkarpov15 the workaround works fine. Are you planning to fix this behaviour or should I adopt the workaround as a permanent solution?
In the case you plan to fix it, any idea on the timing?

Planning a release middle of next week, should have a fix for this by then.

Hmm @enrichz below script works fine for me, can you modify it to see if you can reproduce this issue?

'use strict';

Error.stackTraceLimit = Infinity;

var assert = require('assert');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/gh4529');
mongoose.set('debug', true);

var cardSchema = new Schema({
  title: {
    type: String,
    required: true
  },
version: {
    type: Number,
    required: true,
    "default": 0
  },
  board: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Board'
  },
},{strict: false});
var Card = mongoose.model('Card', cardSchema);

Card.remove({}, function(error) {
  assert.ifError(error);
  Card.create({ board: '000000000000000000000000', title: 'test' }, function(error, doc) {
    assert.ifError(error);
    var cardChanges = {board: null, version: 10};
    Card
      .findOneAndUpdate({_id: doc._id}, cardChanges,
          {"new": true, upsert: false, passRawResult: false,
            "overwrite": false, runValidators: true, 
             setDefaultsOnInsert: true})
      .exec(function(err, result) {
        console.log('done', result);
        process.exit(0);
      });
  });
});

Sorry for the late reply.
I actually tried to recreate the error but I couldn't do it and I don't have the original scenario because I used the workaround you suggested which works well.
Thanks for your time anyway.

@vkarpov15 I can actually reproduce it.
I want to unset all null fields that are passed to Mongosee. Can Mongosee handle that out of the box?

Mongosee version: 5.0.17
Node version: 10.0.0
Mongo version:

$ mongod --version
db version v3.6.4
git version: d0181a711f7e7f39e60b5aeb1dc7097bf6ae5856
OpenSSL version: OpenSSL 1.0.2g  1 Mar 2016
allocator: tcmalloc
modules: none
build environment:
    distmod: ubuntu1604
    distarch: x86_64
    target_arch: x86_64

See Mongo result:

> show collections
cards
groups
users
> db.cards.findOne();
{
        "_id" : ObjectId("5b01ab846f95362cfefc60b3"),
        "version" : 10,
        "board" : null,
        "title" : "test",
        "__v" : 0
}

@SamuelSanchez I don't understand your question, can you please clarify with some code samples?

@vkarpov15 I used you code sample.
I want momgosee to $unset the null values in Mongo. Is there a way for it?
I copied and executed your code and the field cardChanges.board was stored in Mongo with null value, rather than removing the ‘board’ key.

You need to structure the $unset on your own with Model.update(), but you can do it with mongoose

@vkarpov15 Ok so there’s not easy way to just pass a model with null values and expect Mongosee to understand that those null values are to be unset. Or how can it be done with Mongosee? Please provide an example or reference.

Thanks,
Samuel

Here's a general idea:

const { $set, $unset } = update;
for (const prop of Object.keys($set)) {
  if ($set[prop] == null) {
    delete $set[prop];
    $unset[prop] = 1;
  }
}

@vkarpov15 Yes, I did that. That’s how I have been doing it. Thanks!

Happy to help :+1:

options just add: { overwrite: true }

Was this page helpful?
0 / 5 - 0 ratings