How to update multiple documents? - node.js

I want to update multiple documents.
My current Document,
Document Account
{
"_id" : "5cbd96aca1a6363473d4g8745",
"contact" : [
"5cbd96aca1a6363473d4a968",
]
},
{
"_id" : "5cbd96aca1a6363473d4g8746",
"contact" : [
"5cbd96aca1a6363473d4z7632",
]
}
I need below output,
update contact array with different _id.
Document Account
{
"_id" : "5cbd96aca1a6363473d4g8745",
"contact" : [
"5c98833f98770728a7047f1a",
"5cbd96aca1a6363473d4a968",
]
},
{
"_id" : "5cbd96aca1a6363473d4g8746",
"contact" : [
"5caddf78b8c0645402090536",
"5cbd96aca1a6363473d4z763",
]
}

Use $addToSet or $push to push id with bulk update.

You can use update with upsert. It will update the doc if exist and if not then it will create new one.
for example:
//Make a obj to set
var contacts = {
id: req.body.id,
contactIds: req.body.contactIds,
};
req.app.db.models.ModelsName.update(
{
//if you want multiple fields to be update
$and: [{ id: contacts.id }, { contactIds: { $in: contacts.contactIds } }]
},
//Set the above obj
{ $set: contacts },
{ upsert: true },
(err, result) => {
if (err) {
console.log(err.message)
}
console.log("Updated successfully")
})
This is just a reference. Modify accordingly your use.

You can use Bulk.find.update() method to update all matching documents.
example:
var bulk = db.items.initializeUnorderedBulkOp();
bulk.find( { status: "D" } ).update( { $set: { status: "I", points: "0" } } );
bulk.find( { item: null } ).update( { $set: { item: "TBD" } } );
bulk.execute();

Related

findOneAndUpdate is not working inside array

I'm trying to update the document in the MongoDB collection but it's not working for me. Here is the function all fields come to the backend.
{
"_id" : ObjectId("59a6b381c13a090c70fc21b6"),
"processNumber" : "FEE 082517",
"System" : "abc",
"TaxAmount" : 0,
"TaxPercent" : 0,
"Currency" : "USD",
"ProcessData" : [
{
"_id" : ObjectId("59ee2873b1621419a03fba6c"),
"KDSID" : "1db1d4b8-61bc-45eb-bf6d-15af1e391df5"
},
{
"_id" : ObjectId("59ee2873b1621419a03fba6d"),
"KDSID" : "aa9ccaf3-a638-4013-afdc-ccf0a39361e8"
},
{
"_id" : ObjectId("59ee2873b1621419a03fba6e"),
"KDSID" : "4c5e32a7-e2fb-4fe9-998f-e22602e46dba"
}
{
"Name" : "2017 Calc.xlsx",
"FileID" : "59ee2873b1621419a03fb9b7",
"_id" : ObjectId("59ee2873b1621419a03fba75")
}
]
}
Query:
db.process.findOneAndUpdate(
{ 'ProcessData._id': ObjectId("59ee2873b1621419a03fba75"),'ProcessData.FileID': { '$exists': true, '$ne': null }},
{ $set: { 'ProcessData.$.IsFailed': "Yes" } }
)
When I run the above query IsFailed is not updating. can you please advise?
I have tried in node and MongoDB and it's not working.
If ProcessData._id matches with the given id and ProcessData.FileID exist we have to set IsFailed Yes
here's my version with $elemMatch
db.process.updateOne(
{
ProcessData: {
$elemMatch: {
_id: ObjectId("59ee2873b1621419a03fba75"),
FileID: {
$exists: true,
$ne: null
}
}
}
},
{
$set: { "ProcessData.$.IsFaild": "Yes" }
})
https://mongoplayground.net/p/3LBlw9kA6Gl
You need to use arrayFilter when you modify the array.
db.collectionName.updateOne(
{
'ProcessData._id': ObjectId("59ee2873b1621419a03fba75"),
'ProcessData.FileID': { '$exists': true, '$ne': null }
},
{
$set:{"ProcessData.$[p].isFailed": "Yes"}},
{
arrayFilters:[{"p._id":ObjectId("59ee2873b1621419a03fba75")}]
}
)
You're querying through an array of embedded documents, and hence by using elemMatch to find the specific id and perform needed operation on that document should be implemented for example as below:
db.process.updateOne(
{
ProcessData: {
$elemMatch: {
_id:
ObjectId("59ee2873b1621419a03fba75"),
}
}
},
{
"ProcessData.FileID": {
$exists: true,
$ne: null
}
},
{
$set: {
"ProcessData.$.IsFailed": "Yes"
}
})

how to use aggreate query using in mongodb?

I have the following documents in my collection. Need to get all employees in stores using the aggregate function.
//Store 1
{
"_id" : ObjectId("5b0d3fa6b426ea12ec0f6e5a"),
"store_name": KFC
"employees":[
ObjectId("5b0d4c5ec47e6223a08af5fd"), //query id
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
],.. },
//Store 2
{
"_id" : ObjectId("5b0d3fa6b426ea12ec0f6e5a"),
"store_name": McDonalds
"employees":[
ObjectId("5b0d4c5ec47e6223a08af5fd"),
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
],.. },
//Store 3
{
"_id" : ObjectId("5b0d3fa6b426ea12ec0f6e5a"),
"store_name": Dominos
"employees":[
ObjectId("5b0d4c5ec47e6223a08af5fd"),
ObjectId("5b1623905bc92d76abfe0ab1"),
ObjectId("5b14e0b1fc1507569f830f7d")
],.. }
Using aggregate function
db.getCollection('stores').aggregate([
{
$match:{
"employees":{
$in:[ ObjectId("5b0d4c5ec47e6223a08af5fd")] //employee_id
}
}
},{
$unwind: "$employees"
},{
$group: {
"_id": null,
"emps": {
$addToSet: "$employees"
}
}
}
])
OUTPUT
{
"_id" : null,
"emps" : [
ObjectId("5b0d4c5ec47e6223a08af5fd"), // employee id
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
ObjectId("5b1623905bc92d76abfe0ab1"),
ObjectId("5b14e0b1fc1507569f830f7d")
]
}
its fine. I need to get this result without the employee queried id. how i handle it.
Here, How can I remove the queried employee id & need to get result like this
{
"_id" : null,
"emps" : [
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
ObjectId("5b1623905bc92d76abfe0ab1"),
ObjectId("5b14e0b1fc1507569f830f7d")
]
}
You can use $filter and repeat your $in condition insinde $not:
db.getCollection('stores').aggregate([
// your pipeline,
{
$addFields: {
emps: {
$filter: {
input: "$emps",
as: "emp",
cond: { $not: { $in: [ "$$emp", [ ObjectId("5b0d4c5ec47e6223a08af5fd")] ] } }
}
}
}
}
])
$addFields is used to replace existing emp field

Mongoose Aggregation match an array of objectIds

I have a schema that Looks like this
var Post = new mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
created: {
type: Date,
Default: Date.now
})
I have a User Table as well. I Have a array of user ids and i am trying to search the post table based on an array of user ids
For Example
var userIds = ["575e96652473d2ab0ac51c1e","575e96652473d2ab0ac51c1d"] .... and so on
I want to return all posts created by these users. And posts should be sorted by their creation date. Is there a way to group this post based on the user ids provided, basically match the posts for an individual user?
The result I am trying to attain is something like this:
[{
userAId : "56656.....",
post : [postA, postB],
},{
userBId :"12345...",
post : [postA, postB]
}]
How do I write this query?
This is what I have so far
Post.aggregate([{
// {"$unwind" : ""},
// "$group": {
// _id: "$author",
// "created" : {"$sum" : 1 }
// }
"$match" : { author : id}
}]).exec(function(error, data) {
if(error){
return console.log(error);
}else{
return console.log(data)
}
})
{
"_id" : ObjectId("575e95bc2473d2ab0ac51c1b"),
"lastMod" : ISODate("2016-06-13T11:15:08.950Z"),
"author" : ObjectId("575dac62ec13010678fe41cd"),
"created" : ISODate("2016-06-13T11:15:08.947Z"),
"type" : "photo",
"end" : null,
"commentCount" : 0,
"viewCount" : 0,
"likes" : 0,
"tags" : [],
"title" : "Today is a good day",
"__v" : 0
}
To return all posts created by users depicted in a list of ids, use the $in operator in your query and then chain the sort() method to the query to order the results by the created date field:
Post.find({ "author": { "$in": userIds } })
.sort("-created") // or .sort({ field: 'asc', created: -1 });
.exec(function (err, data){
if(err){
return console.log(err);
} else {
return console.log(data);
}
});
To get a result where you have the post id's grouped per user, you need to run the following aggregation operation:
Post.aggregate([
{ "$match" : { "author": { "$in": userIds } } },
{ "$sort": { "created": -1 } },
{
"$group" : {
"_id" : "$author",
"posts" : { "$push": "$_id" }
}
},
{
"$project": {
"_id": 0,
"userId": "$_id",
"posts": 1
}
}
]).exec(function (err, result){
if(err){
return console.log(err);
} else {
return console.log(result);
}
});
Or with the fluent API:
Post.aggregate()
.match({ "author": { "$in": userIds } })
.sort("-created")
.group({
"_id" : "$author",
"posts" : { "$push": "$_id" }
})
.project({
"_id" : 0,
"userId" : "$_id",
"posts": 1
})
.exec(function (err, result){
if(err){
return console.log(err);
} else {
return console.log(result);
}
});
This should be possible without aggregation.
Post
.find({ author: { $in: userIds } })
.sort({ created: -1 })
If you get CastError: Cast to ObjectId failed, make sure to map your userIds array from an array of strings to an array of mongoose id's.
userIds = userIds.map(userId => new mongoose.Types.ObjectId(userId))

If condition query for mongo db

I have an collection with documents that can be public or private. I am looking to have a single query that can get a document by an _id and check if it's private. If it is private it needs to check if the user requesting the document is a participant in the object.
Here is the object:
{
"_id" : ObjectId("5769ae620e80ea1c7f8a997f"),
"owner" : ObjectId("5740edae95a1b4c043d033df"),
"private" : false,
"participants" : [
{
"uid" : ObjectId("5740edae95a1b4c043d033df"),
"notify" : true
}
],
"messages" : [ ]
}
This is the 2 step query I wrote and wondering if I can simplify it
function getRoom(roomId, user){
db.rooms.findOne({ _id: pmongo.ObjectId(roomId) })
.then(room => {
if(room.private){
return db.rooms.findOne({
_id: pmongo.ObjectId(roomId),
participants: {$eleMatch: {uid: String(user._id)}}
})
} else {
return room
}
})
}
Any help would be great!
MongoDB has $or operator which can be used in this case:
db.rooms.findOne({ $or: [
{
_id: pmongo.ObjectId(roomId),
private: { $ne: true }
}, {
_id: pmongo.ObjectId(roomId),
participants: {$eleMatch: {uid: String(user._id)}}
}
]})

Create GeoJson from coordinates array in the same Mongodb collection

I want to modify my mongodb collection from 2d to 2dsphere.
I have this structure in my db.users:
{
"_id" : "1c6930387123e960eecd65e8ade28488",
"interests" : [
{
"_id" : ObjectId("56a8b2a72f2c2a4c0250e896"),
"coordinates" : [-3.6833, 40.4]
}
],
}
I would like to have something like this:
{
"_id" : "1c6930387123e960eecd65e8ade28488",
"interests" : [
{
"_id" : ObjectId("56a8b2a72f2c2a4c0250e896"),
"loc":{
"type":"Point",
"coordinates" : [-3.6833, 40.4]
}
}
],
}
I tried this:
db.users.update( {interests:{$elemMatch:{coordinates : { $exists: true } }}}, { $set: { 'interests.$.place':{"type":"Point", "coordinates":'interests.$.coordinates'} } }, { upsert: false, multi: false });
Obviously, it insert literally "'interests.$.coordinates'
And tried this in Node:
users.find({interests:{$elemMatch:
{coordinates :
{ $exists: true } }}} ,
{"interests.coordinates":1,"interests._id":1,"_id":0 }).forEach( function( doc ){
users.update( {interests:
{$elemMatch:
{_id : doc.interests[0]['_id'] }}},
{ $set: { 'interests.$.loc':{"type":"Point", "coordinates":doc.interests[0]['coordinates']} } },
{ upsert: false, multi: false },function(err, numberAffected, rawResponse) {
var modified=numberAffected.result.nModified;
console.log(modified)
});
});
But coordinates were inserted with mixed values.
Thoughts?
Thanks!!
I didn't test this piece of code but I think this would shed light on this issue.
users.find(
{interests:{ $elemMatch: {coordinates : { $exists: true } }}}).forEach( function( doc ){
for(var c = 0; c < doc.interests.length; c++) {
var orig = doc.interests[c].coordinates;
doc.interests[c].loc: { type:"Point", coordinates: orig };
//delete doc.interests[c].coordinates;
};
users.update({ _id: doc._id }, doc);
});
Try to iterate over all documents in your collection modifying the whole document and then update it in a single line.
Warning: If you have a huge quantity of documents in your collection that match the 'find' condition, you should use pagination (skip/limit) to avoid performance and memory issues in the first load.

Resources