Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any way to get the modified IDS from mongodb's bulk operations using mongoose?

let dbOperations = Edge.collection.initializeOrderedBulkOp()
edges.forEach(edge => {
    dbOperations.find({_id: edge.id}).upsert().updateOne({
        $set: {
            value: edge.value
        },
        $setOnInsert: {
            _id: edge.id
        }
    })
})
dbOperations.execute()
    .then(result => {
        console.log(result.nModified) // This shows the number of edges that is actually modified
        console.log(result.getModifiedIds()) // This is what I want to achieve
    })

Any way to achieve this?

like image 594
Martol1ni Avatar asked Dec 08 '15 00:12

Martol1ni


1 Answers

Well from one point of view the anwer is "no" and there is a very good reason for that.

Generally speaking, MongoDB "update" operations are intended to work across what is commonly "multiple" documents, therefore meaning whatever matched the criteria. So the general case here is whatever you either asked to be updated in either singular or by selection was either updated or not depending on whether anything was matched.

In the "Bulk" context, much of the same thing applies, in that there was either a criteria match or not, in which case you will get returned values for nMatched and nModified repectively, as there is also the possibility that a "matched" document is not actually updated where the data present to be modified is already the value which is the target of the modification.

That last distinction between nMatched and nModified is the prime reason why "you cannot reliably do this", since not everything matched is necessarily modified.

You can however make a guestimate value in the case of discerning between "upsert" actions and actual "updates". It won't be 100% acurate because of the noted distintion, but the basic process is to compare your input list to the returned value from getUpsertedIds(), which is a valid call.

Eschewing the ES6 syntax for the rest of the world at present:

var upserted = result.getUpsertedIds();    // get this from the bulk result

upserted = upserted.map(function(up) { return up._id }); // filter out just the _id values

var modifiedIds = edges.map(function(edge) {    // get _id only from source 
    return edge.id;  
}).filter(function(edge) {
    return upserted.indexOf(edge) == -1;        // and return only non upserted
});

Where the returned result of from .getUpsertedIds() is an array of objects containing both the "index" position from the bulk update and the generated or supplied _id value of the "upsert".

[ { index: 0, _id: 1 } ]

So matching out your input list against the "upserted" list to see "what is not there", basically returns things that where probably just modified. With of course the caveat that if the value was already the same as the modification, then it really was not a modification at all.

But due to how the API is meant to work, that's as close as you are going to get.

like image 87
Blakes Seven Avatar answered Oct 16 '22 08:10

Blakes Seven