Mongoose and bulk update - node.js

First time working with MongoDB and Mongoose.
I have written an edit function which do something with the input params and then call an update on the model:
edit: function (input) {
var query = ...
var document = ...
return Model.update(query, document, {multi: true});
}
The function return a Promise with the number of affected documents.
I know that the Mongoose update function
updates documents in the database without returning them
so I was wondering if there is a way to somehow:
run my edit function
if everything goes well, run a find on the model in order to retrieve the updated documents, and return the find's Promise.
Any help would be appreciated.

Related

is changed function in sequelize like isModified in mongoose?

mongoose isModified functionIn a hook I want to confirm whether a password has changed before executing encryption process. Mongoose has a function "isModified" and I believe Sequelize's "changed" function servers the same purpose.
I cannot get the "changed" function to work. I am looking for an example of how it is used.
There is an example of how changed() works in the official documentation
const mdl = await MyModel.findOne();
mdl.myJsonField.a = 1;
console.log(mdl.changed()) => false
await mdl.save(); // this will not save anything
mdl.changed('myJsonField', true);
console.log(mdl.changed()) => ['myJsonField']
await mdl.save(); // will save
Keep in mind that changes are detected for the top-level fields and only for changes that were made since the last save call.

Modify data in mongoose pre-validate hook

I would like to modify a document field's data prior to it being validated by mongoose, like so:
mySchema.pre("validate", function (next) {
this.myField = "yay a new value prior to validation" // doesn't work for me
next();
});
Unfortunately, that doesn't work for me. The example above is simplified, in my project I'm trying to prevent an ObjectParameterError from crashing my server, and assigning values in my pre-validate hook doesn't work for me.
Try using .set() method of mongoose Document to access value. Your code should be changed this way
mySchema.pre("validate", function (next) {
this.set("myField", "yay a new value prior to validation")
next();
});

MongoDB bulk.execute() promise neither resolves nor rejects and bulkWriteResult isn't being returned

MongoDB version 3.6.7, mongoDB node.js driver version 3.1.10.
Have a function which should add some data to the db in a bulk unordered operation. When bulk.execute() is called the data is inserted into the DB as have manually checked this is the case, however the bulkWriteResult object which should be generated as a result of the execution isn't being returned.
We need that for use in other functions to determine the number of insertions etc. So when the function in question is chained in other functions it returns undefined, when adding bulk.execute().then(console.log) also nothing is logged to the terminal.
The function takes 3 parameters, the MongoClient, the name of the collection and the documents to be inserted into the DB which is an array of documents.
Have also tried adding err and result callbacks too with no luck, none of the console.logs are reached.
batch.execute((err, result) => {
console.log('RESULT INSERTED:', result.nInserted)
console.log('RESULT ERRORS:', result.getWriteErrorCount())
console.log('RESULT INSIGHTS:', result.getWriteErrors())
console.log('ERROR:', err)
})
Any ideas why the bulkWriteResult would not be returned yet the bulk insertion is successful?, function was working and returning the expected object prior to upgrading the mongoDB node driver to 3.1.10.
const insertManyMissingEntries = (database, collectionName, documents) => {
const db = database.db('data')
const collection = db.collection(collectionName)
const batch = collection.initializeUnorderedBulkOp()
documents.forEach(doc => {
batch
.find({ year: doc.year, month: doc.month, code: doc.code })
.upsert()
.updateOne({ '$setOnInsert': doc })
})
return batch.execute()
}
Here is your function
const insertManyMissingEntries = (database, collectionName, documents) => {
if (documents.length === 0)
return Promise.reject('documents length is zero')
const operations = documents.map((doc) => {
const filter = {year: doc.year, month: doc.month, code: doc.code}
const update = {$setOnInsert: doc}
return {updateOne: {'filter': filter, 'update': update, 'upsert': true}}
})
const db = database.db('data')
const collection = db.collection(collectionName)
const bulkOptions = {ordered: false}
return collection.bulkWrite(operations, bulkOptions)
}
If documents parameters is empty i.e. length = 0 the collection bulk write function will always fail. Watch it.
Also you need to make sure you have index on fields year, month, code or your bulk will be executing slow because it will every time it will perform a collection scan to find a document.
Remember,
driver docs is your best friend
http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html
There wasn't a way to resolve this issue though we believe it was caused by a docker mongo image version not being the official one or out of date. Even the folks at mongoDB weren't able to replicate this or explain any circumstances where a promise should fail to either resolve or reject within the timescales the functions were working to so like many things it remains a mystery that we had to workaround by basically using a ternary to handle the undefined that resulted from the promise error without ever actually solving the underlying issue - not ideal or best practice but in absence of other options it's what we did.
Thanks for everyone's help and comments to try to resolve it, much appreciated.

How to do a atomic find and save using mongoose in Node.js

In my db, I have a "Thing", whose id is "53e5fec1bcb589c92f6f38dd".
I wanna update the count member in it everytime when doAdd is called.
Like the code below.
But since the find and save operation is separated, I cannot get the desired result..
Any best practice about this situation?
Thanks in advance!
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var ThingSchema = new mongoose.Schema({
count: Number,
});
var Thing = mongoose.model('Thing', ThingSchema);
var doAdd = function(id){
Thing.findById(id, function(err, thing){
if(******){
#perform some logic...
thing.count++;
}
thing.save();
});
};
var id = "53e5fec1bcb589c92f6f38dd";
doAdd(id);
doAdd(id);
The problem is you are expecting to increase the count by 2 as you are calling doAdd twice. But here the code in doAdd is of asynchronous nature i.e the second doAdd call is called before the the first query and save process is completed. The results are unpredictable due to the asynchronous nature of the function. All mongoose queries and the save calls are asynchronous.
So if you call
thing.save();
console.log('saved!!');
The console ouput appears before the document is actually saved because node doesn't wait for the save to be finished. So if you need any operation to be done after the document is saved, you would place it in the callback.
thing.save(function(err){
if(!err){
console.log('saved');
}
});
If you want to avoid callbacks have a look at async module.

syncronous query in mongodb (+mongoose) + node.js

I have a mongoose schema. I want to count records in a collection that corresponds to the schema. I don't want to count all records, but records that satisfies some criteria. How to execute this count synchronously?
In mongodb console I can do `db.mycollections.find(criteria).count()". How to
execute this query from mongoose code?
Mongoose, like most nodejs modules, is not designed to be used for synchronous code execution. This would result in all of the app's execution stalling while the database is performing the query, which could be a long time.
There is an asynchronous count function which you call on your model.
Assuming you made a model from your schema like so:
var MyModel = mongoose.model('mySchemaCollection', mySchema);
You can get the count like so:
MyModel.count(criteria, function (err, count) {
/* handle count */
});
You can read more about count, as well as other types of querying, from the Mongoose Documentation.

Resources