Mongoose: Timestamps and bulkWrite for insertOne

Created on 13 Oct 2017  ·  28Comments  ·  Source: Automattic/mongoose

file: ReportModel.js

const newSchema  = new Schema({
counter: {type: Number, default: 0},
name: {type: String, default: 'nothing' },
country: String
}, {versionKey: false});

module.exports = connection.model('reports', newSchema);

file: another-job.js

  await ReportModel.updateOne(recordConditions, {
        $inc: {
          'counter': 1
        },
      }, { upsert: true, setDefaultsOnInsert: true });

- result: upsert and setDefaultsOnInsert works here.

file: job.js

const reportOperations = [];

const filter = {
 country: 'US',
};

reportOperations.push({
     updateOne: {
       filter,
       update: {
         $inc: {
           'counter': 1,
         },
       },
       upsert: true,
      setDefaultsOnInsert: true,
     },
});

await ReportModel.bulkWrite(reportsOperations);

the upsert works here, but what seems to not work is the setDefaultsOnInsert.

the upserted record has no report.name property.

Whats needs to be done here?

sources:

confirmed-bug

Most helpful comment

Fix will be in 5.2.14 :+1:

All 28 comments

Thanks for reporting, will investigate

Confirmed, here's the repro script:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

mongoose.set('debug', true);
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/test', { useMongoClient: true });

const newSchema = new Schema({
  counter: {type: Number, default: 0},
  name: {type: String, default: 'nothing' },
  country: String
}, {versionKey: false});

const ReportModel = mongoose.model('reports', newSchema);

run().catch(error => console.error(error.stack));

async function run() {
  const reportOperations = [];

  const filter = {
    country: 'US',
  };

  reportOperations.push({
    updateOne: {
      filter,
      update: {
        $inc: {
          'counter': 1,
        },
      },
      upsert: true,
      setDefaultsOnInsert: true,
    }
  });

  await ReportModel.bulkWrite(reportOperations);
}

Looks like we don't do setDefaultsOnInsert in bulkWrite(). Still working on a fix :+1: :palm_tree:

thanks @vkarpov15, its working now.

@vkarpov15 not working for me... what's the reason?

@ashishlal91 please provide code samples, if you don't give me some idea of what your code looks like I can't provide much help.

@vkarpov15 Thank you for the reply... Here is my code

const createInvite = await Invite.bulkWrite(
        payload.invites.map((invite) => 
          ({
            updateOne: {
              filter: { sender: user, receiver: invite, status: 2, senderWorkoutId: addWorkout._id }, //requested
              update: { sender: user, receiver: invite, status: 2, senderWorkoutId: addWorkout._id, author: user },
              upsert: true, setDefaultsOnInsert: true, runValidators: true
            }
          })
        )
      )

Collection is being created from the above code but the createdAt and updatedAt field not being inserted. I have put the setDefaultsOnInsert but it doesn't work and also I have put timestamps: true in schema... Please help

mongoose version --> 5.1.2
mongodb version --> 4.x

Do I need to update mongoose version?

@vkarpov15 Any updates

@vkarpov15 hello!I meet the same as problem。
the Schame member as:

new Schame("Member",{
    name:string,
    type:number,
    creator:{
        name:string,
        age:number
    }
},{timestampz:true})

I want to bulk write the data memberUnLean as

[
    {
        name:"asdfasd",
        type:1,
        from:"asdfadsf",
        creator:{
            name:"asdfa",
            age:21,
            position:"asdfasdf",
            createdBy:"asdfasdf",
            createdAt:"asdf",
            updatedBy:"asdf",
            updatedAt:"asdf",
        }
    },
    ...
]

then I write the under code to bulk write

Member.bulkWrite([
    {
        filter:{..},
        update:(new Member(memberUnLean)).toObject(),
        setDefaultsOnInsert: true,
        upsert: true,
    }
])

but the data in DB loss createdAt and updatedAt.:bug:

Thank you!:see_no_evil:

Oh ok so the problem is timestamps not getting updated on bulkWrite? We will look into that, thanks for reporting

@vkarpov15 yes the timestamps is not getting inserted or updated in the database on upsert: true and also the default values. This might be the problem with the setDefaultsOnInsert. Anyway thanks for reopening the issue.

@ashishlal91 @vkarpov15 And here has an other question,:sweat_smile:
the DataUnLean Object want to change the member model object.
I write a line code.
(new Member(memberUnLean)).toObject().
emmm,Can I ask for you,
Mongoose have more convenient Function in this case,static Function such as...
thank you very much! :smiley:

@halu886 I don't understand your question, can you please clarify?

@vkarpov15 oh,sorry
I mean,there is a not lean Data memberUnlean

{
        name:"asdfasd",
        type:1,
        from:"asdfadsf",
        creator:{
            name:"asdfa",
            age:21,
            position:"asdfasdf",
            createdBy:"asdfasdf",
            createdAt:"asdf",
            updatedBy:"asdf",
            updatedAt:"asdf",
        }
}

I want to change it to model Object

new Schame("Member",{
    name:string,
    type:number,
    creator:{
        name:string,
        age:number
    }
},{timestampz:true})

{
    name:string,
    type:number,
    creator:{
        name:string,
        age:number
    }
}

so I try it by (new Member(memberUnLean)).toObject()
I have the question that it has better way?😅

Still not sure exactly what you're asking, but perhaps try Model.hydrate() ?

@vkarpov15 how much it will take to resolve this issue? thanks

@halu886 in your example above you have {timestampz:true}. I think that should be {timestamps:true}

I also have the problem that timestamps (updatedAt) not updated when I use findByIdAndUpdate mongoose function.

This is my schema:

export const BagSchema = new mongoose.Schema({...}, { timestamps: true, });

and when I updated data with:

this.bagModel.findByIdAndUpdate(bag._id, bag, { new: true, runValidators: true })

updatedAt not change.

@vkarpov15 Any updates?

@ashishlal91 I just looked at your comment above with the code sample. It has this line:

but it doesn't work and also I have put timeStamp: true in schema... Please help

it should be timestamps: true.

@lineus It was a typo in comment. I have put the same timestamps: true in schema

Fix will be in 5.2.14 :+1:

@lineus thanks for pointing this out, you were right, we needed to call initializeTimestamps() to make sure createdAt and updatedAt get set for insertOne and replaceOne.

@vkarpov15 setDefaultsOnInsert is not working on bulkWrite again in 5.3.4 but did in all prior versions we tried were as we've used it for a while. Let me know what you need to diagnose.

@rogerkirkness can you elaborate on what you mean by "not working"? Can you point to an existing example, or modify this one to reproduce what you're seeing?

It doesn't set defaults, it just silently fails to. I haven't changed the code, it just changed behaviour.

@rogerkirkness can you provide some code samples, or better yet open up a new issue and follow the instructions? We have tests for setDefaultsOnInsert and they're passing

Also seeing this behaviour:

const bulkOps = docsArray.map(doc => ({
         updateOne: {
             filter: { email: doc.email },
             update: { $set: doc },
             upsert: true,
             setDefaultsOnInsert: true
          }
      }));
      insertResults = await model.Customer.bulkWrite(bulkOps)

Write is successful, but defaults not applied. You can use whatever schema you want, have tried with different ones, result is the same; fails silently.

Running mongoose 5.3.14

@sashahilton00 ah so your issue is with defaults, not timestamps. Will open a separate issue to track

Was this page helpful?
0 / 5 - 0 ratings