Miguel Zamora Lopez
Miguel Zamora Lopez

Reputation: 21

Creating a Mongoose BulkWrite Plugin

I'm struggling with the bulkWrite operation. I'm trying to create a bulk of operations that upsert documents in my collection. For each document created a plugin is utilised.

const documents = [];
const count = 1000;
for (let i = 0; i < count; i++) {
    documents.push(
        {
            updateOne:
            {
                filter: { itemId: i },
                update: { $set: { name: i } },
                upsert: true
            }
        }
    );
}
await MyModel.bulkWrite(documents);

Each document needs to have an updated at date for when the document as either created or updated. For that I use a plugin.

const plugin = function updateAtPlugin(schema: any, options: any) {
    schema.add({ updatedAt: Date });
    schema.post('updateOne', function (next: any) {
        this.updatedAt = new Date;
        next();
    });
    if (options && options.index) {
        schema.path('updatedAt').index(options.index);
    }
};
export default plugin;

This plugin is then used before the model is created.

import { Schema, model } from 'mongoose';
import updatedAtPlugin from './update-plugin';
const MySchema: Schema = new Schema({
    itemId: {
        type: String,
        required: true,
        index: true
    },
    attributes: Object
});
MySchema.plugin(updatedAtPlugin);

const MyModel: any = model('my-name', MySchema);
export { MyModel };

In addition to the bulkWrite function I've also tried initializeUnorderedBulkOp in combination with find.upsert().updateOne().

In both cases the plugin is not working.

I would really appreciate some help.

Thanks in advance

------- EDIT ------

I'd like to elaborate on my use case. The goal is to have a flag set as true for all new and updated documents and utilising a mongoose plugin to do so.

const plugin = function updated(schema: any, options: any) {
    schema.post('updateOne', function (next: any) {
        this.flag = true
        next();
    });
    if (options && options.index) {
        schema.path('flag').index(options.index);
    }
};
export default plugin;
import { Schema, model } from 'mongoose';
import updated from './updated-plugin';
const MySchema: Schema = new Schema({
    itemId: {
        type: String,
        required: true,
        index: true
    },
    attributes: Object,
    flag: {
       type: Boolean, 
       default: true
    }
});
MySchema.plugin(updated);

const MyModel: any = model('my-name', MySchema);
export { MyModel };

The reason why is because the bulkWrite doesn't send back the upserted documents. It only returns a modified count. I'd like to execute a query MySchema.find({flag: true}) loop through the result, do some magic and then set the flag to false for each processed item.

In addition to a plugin I've also tried setDefaultsOnInsert and setOnInsert. Unfortunately without success.

Upvotes: 1

Views: 411

Answers (1)

Hafez
Hafez

Reputation: 1440

You don't need a custom plugin, mongoose has that built in.

Adding { timestamps: true } as a second argument to your schema adds createdAt and updatedAt automatically to all your documents.

const MySchema: Schema = new Schema({
    itemId: {
        type: String,
        required: true,
        index: true
    },
    attributes: Object
}, { timestamps: true });

Upvotes: 1

Related Questions