mongoose multi update in one query - node.js

is there please any way to perform this query in mongoose?
this multi update is possible from mongodb v2.6
{
update: <collection>,
updates:
[
{ q: <query>, u: <update>, upsert: <boolean>, multi: <boolean> },
{ q: <query>, u: <update>, upsert: <boolean>, multi: <boolean> },
{ q: <query>, u: <update>, upsert: <boolean>, multi: <boolean> },
...
],
ordered: <boolean>,
writeConcern: { <write concern> }
}
i found this topic, but its pretty old: Mongodb multi update with different value
thx everyone for suggetions

From the details that you provided, I assume that you would like to issue a series of update queries based on several different criteria and specific update values for each particular query.
Nevertheless, I will address both possible scenarios when it comes to updating multiple documents in MongoDB.
As I previously mentioned, if you would like to update multiple documents, there are two possible scenarios:
Update multiple documents that match one set of specific criteria, case in which you can use db.collection.update(), by specifying the multi parameter when you fire your operation Official MongoDB Docs
Use bulk.find.update() to chain several multi update operations and execute them in bulk Official MongoDB Docs

ok these are the results
var p_text_data = require("../public/import/p_100_k_text_cz.json"); //data with new vals
_und.map(p_text_data,function(vals,index) {
var new_name = vals.name + something;
e_textModel.collection.update({ 'id': vals.id }, { $set: { 'name': new_name } }, {upsert: false, multi: true});
});
using sinle update every iteration, updating 100k documents take about 7+ seconds
and next code, using bulk, take less than 3 seconds
var bulk = e_textModel.collection.initializeUnorderedBulkOp();
_und.map(p_text_data,function(vals,index) {
ite++;
var new_name = vals.name + something;
bulk.find( { 'id': vals.id } ).update( { $set: { 'name': new_name } } );
});
bulk.execute();
EDIT:
$var bulk = e_textModel.collection.initializeOrderedBulkOp();
is even couple times faster then UnorderedBulkOp in this case

Related

using updateOne inside a map, setting the filter to the unique id , $set is to the document and upsert is true. Even then new document is created

here is my code in the controller from where i am getting the records from my google calendar API and then passing that data to this function and the code inside the function which inserts the document (records) looks like this as below:
Holiday.bulkWrite(
holidays.map((holiday) => ({
updateOne: {
filter: { holidayId: holiday.id },
update: { $set: holiday },
upsert: true,
},
}))
)
It's hard to tell what exactly the issue is because it is not Mongo related but code related, from what it seems you are just using the wrong field for the filter.
holiday.id is null, and we can see that the "inserted" documents do not have such field. You are basically executing the following update:
db.collection.update({
holidayId: null
},
{
"$set": {
holidayId: "123"
... other fields
}
},
{
"upsert": true
})
I believe this simple fix would solve your issue, change .id To .holidayId:
Holiday.bulkWrite(
holidays.map((holiday) => ({
updateOne: {
filter: { holidayId: holiday.holidayId },
update: { $set: holiday },
upsert: true,
},
}))
)

MongoDB Update & Aggregate Problem: Skipping over aggregation

I have two tables, one for messages to be logged and one that is for each member of the group. When a message is upvoted, I want to add an entry for the message and push each reaction on that message to an array.
Every time a reaction is added I want to update the member table to reflect the sum of all of the reaction.value fields.
This is the code I have written to do so. When this runs from a sandbox I made in VisualStudio using a MongoDB add on it runs fine, however when ran using my app, only the message document is added and without any error it appears to skip the aggregation to the member document.
Here is the code I am using to insert the documents to the database and to aggregate once the document is inserted:
await mongodb.collection("Messages").updateOne({ _id: reaction.message.id.toString()},
{
$set:{
authorid: reaction.message.author.id,
author: reaction.message.author.username
},
$push: {
reactions: {
reauth: reAuth,
reaction: reaction.emoji.name,
removed: false,
value: actualKarmaDB,
}
}
}, {safe: true, "upsert": true})
await mongodb.collection("Messages").aggregate([
{
$match: {
_id: reaction.message.id
}
},
{
$project: {
_id: "$authorid",
username: "$author",
messageKarma: {$sum: "$reactions.value"},
}
},
{ $merge: {
into: "Members",
on: "_id",
whenMatched: "replace",
whenNotMatched: "insert"
}
}])
Also here is a look at what the insertion into “Messages” looks like:
In this case the answer was due to mongoose not supporting merge for aggregation. Had to use $out.
Additionally this is a known issue with Mongoose Node.js, see here:
Mongodb node.js $out with aggregation only working if calling toArray()

Mongoose: Update/Insert in nested subdocument

I've seen quite a few examples here in stackoverflow, but none of them have been useful to me. Maybe my scheme is wrong?
I need to insert new records into a nested document using Mongoose (I would like to add within the "history" array). If the document already exists, I must only update it, if it does not exist, a new document must be added. I have the following scheme:
let equipment_json = {
controls: [{
_id: con.Schema.Types.ObjectId,
name: String,
history: [{
_id: con.Schema.Types.ObjectId,
new: Boolean,
}]
}]
};
let equipment_schema = new con.Schema(equipment_json);
let Equipment = con.mongoose.model('Equipment', Equipment_schema);
This code should perform the update:
Equipment.update({
'_id': object_equipment.id_equipment,
'controls._id': object_equipment.id_control_type
},{
$set: {
'controls.$.history.$': {
new: true
}
}
},
{
upsert: true, setDefaultsOnInsert: true
},
function (err, doc ) {
console.log( doc );
})
Before using update() I used find() to check what it finds according to the criteria. Using find(), it returns the document, however, when I want to use update() it does not add to the array "controls", the "new": "true". I tried as much with $set as with $push.
It's only necessary to modify the following code:
'controls.$.history.$': {
new: true
}
by
'controls.$.history': {
new: true
}

Mongoose update first five documents

Hello I am trying to update only first five documents from my schema using mongoose. I found a way to update documents by giving condition but cant update only first five.
I got this code
mongoose.model('person').update( {active:false} , {multi: true} , function(err,docs) { ... });
Thank you
The key here is to get the first 5 _id values matching your condition and then pass those using $in to your update selection:
mongoose.model('person').find({ "active": { "$ne": false }}).limit(5)
.exec(function(err,docs) {
var ids = docs.map(function(doc) { return doc._id } );
mongoose.model('person').update(
{ "_id": { "$in": ids } },
{ "$set": { "active": false } },
{ "multi": true },
function(err,numAffected) {
}
);
});
Also notice the correct arguments to the update statement with a "query" and "update" block. You should also be using update operators such as $set, otherwise you are overwriting the existing document content with just the contents of the "update"block.
Also see the .update() method from the core documentation.

Sorting by virtual field in mongoDB (mongoose)

Let's say I have some Schema which has a virtual field like this
var schema = new mongoose.Schema(
{
name: { type: String }
},
{
toObject: { virtuals: true },
toJSON: { virtuals: true }
});
schema.virtual("name_length").get(function(){
return this.name.length;
});
In a query is it possible to sort the results by the virtual field? Something like
schema.find().sort("name_length").limit(5).exec(function(docs){ ... });
When I try this, the results are simple not sorted...
You won't be able to sort by a virtual field because they are not stored to the database.
Virtual attributes are attributes that are convenient to have around
but that do not get persisted to mongodb.
http://mongoosejs.com/docs/2.7.x/docs/virtuals.html
Virtuals defined in the Schema are not injected into the generated MongoDB queries. The functions defined are simply run for each document at the appropriate moments, once they have already been retrieved from the database.
In order to reach what you're trying to achieve, you'll also need to define the virtual field within the MongoDB query. For example, in the $project stage of an aggregation.
There are, however, a few things to keep in mind when sorting by virtual fields:
projected documents are only available in memory, so it would come with a huge performance cost if we just add a field and have the entire documents of the search results in memory before sorting
because of the above, indexes will not be used at all when sorting
Here's a general example on how to sort by virtual fields while keeping a relatively good performance:
Imagine you have a collection of teams and each team contains an array of players directly stored into the document. Now, the requirement asks for us to sort those teams by the ranking of the favoredPlayer where the favoredPlayer is basically a virtual property containing the most relevant player of the team under certain criteria (in this example we only want to consider offense and defense players). Also, the aforementioned criteria depend on the users' choices and can, therefore, not be persisted into the document.
To top it off, our "team" document is pretty large, so in order to mitigate the performance hit of sorting in-memory, we project only the fields we need for sorting and then restore the original document after limiting the results.
The query:
[
// find all teams from germany
{ '$match': { country: 'de' } },
// project only the sort-relevant fields
// and add the virtual favoredPlayer field to each team
{ '$project': {
rank: 1,
'favoredPlayer': {
'$arrayElemAt': [
{
// keep only players that match our criteria
$filter: {
input: '$players',
as: 'p',
cond: { $in: ['$$p.position', ['offense', 'defense']] },
},
},
// take first of the filtered players since players are already sorted by relevance in our db
0,
],
},
}},
// sort teams by the ranking of the favoredPlayer
{ '$sort': { 'favoredPlayer.ranking': -1, rank: -1 } },
{ '$limit': 10 },
// $lookup, $unwind, and $replaceRoot are in order to restore the original database document
{ '$lookup': { from: 'teams', localField: '_id', foreignField: '_id', as: 'subdoc' } },
{ '$unwind': { path: '$subdoc' } },
{ '$replaceRoot': { newRoot: '$subdoc' } },
];
For the example you gave above, the code could look something like the following:
var schema = new mongoose.Schema(
{ name: { type: String } },
{
toObject: { virtuals: true },
toJSON: { virtuals: true },
});
schema.virtual('name_length').get(function () {
return this.name.length;
});
const MyModel = mongoose.model('Thing', schema);
MyModel
.aggregate()
.project({
'name_length': {
'$strLenCP': '$name',
},
})
.sort({ 'name_length': -1 })
.exec(function(err, docs) {
console.log(docs);
});

Resources