mongojs replacing document with update command - node.js

With mongojs we need to update the document with something like below given code
db.data.update(
{
"title": {$regex : '.*Green Red.*', $options : 's'},
"editor.key": {"$in": ["74014","45339"]},`enter code here`
"types" : "Notes"
},
{
$set: {
"editor.key": "05335",
"editor.value": "editor1",
"editor.email": "editor1#gmail.com"
}
},
false,
true
);
But the problem is its really not dynamic
exports.updatePerson = function(Person , onDone) {
Person.UpdatedOn = new Date();
db.people.save(nodd, function (err) {
onDone();
});
But its creating a duplicate record

try this :
db.data.update(
{
"title": {$regex : '.*Green Red.*', $options : 's'},
"editor.key": {"$in": ["74014","45339"]},`enter code here`
"types" : "Notes"
},
{
$set: {
"editor.key": "05335",
"editor.value": "editor1",
"editor.email": "editor1#gmail.com"
}
},{
insert:false,
multi : true
}
);
insert and multi parameter should be fields of an object

Related

Prevent mongoose "Model.updateOne" from updating ObjectId(_id) of the model when using "$set"

I'm updating the age and name of a character with a specific _id from an array of characters that is inside a document of model Drama.
The document I'm working with:-
{
"_id" : ObjectId("619d44d2ec2ca20ca0404b5a"),
"characters" : [
{
"_id" : ObjectId("619fdac5a03c8b10d0b8b13c"),
"age" : "23",
"name" : "Vinay",
},
{
"_id" : ObjectId("619fe1d53810a130207a409d"),
"age" : "25",
"name" : "Raghu",
},
{
"_id" : ObjectId("619fe1d53810a130207a502v"),
"age" : "27",
"name" : "Teju",
}
],
}
So to update the character Raghu I did this:-
const characterObj = {
age: "26",
name: "Dr. Raghu",
};
Drama.updateOne(
{ _id: req.drama._id, "characters._id": characterId },
{
$set: {
"characters.$": characterObj,
},
},
function(err, foundlist) {
if (err) {
console.log(err);
} else {
console.log("Update completed");
}
}
);
// req.drama._id is ObjectId("619d44d2ec2ca20ca0404b5a")
// characterId is ObjectId("619fe1d53810a130207a409d")
This updated the character but it also assigned a new ObjectId to the _id field of the character. So, I'm looking for ways on how to prevent the _id update.
Also, I know I can set the individual fields of character instead of assigning a whole new object to prevent that but it will be very tedious if my character's object has a lot of fields.
//Not looking to do it this way
$set: {
"characters.$.age": characterObj.age,
"characters.$.name": characterObj.name,
},
Thanks.
I found something here, just pre define a schema (a blueprint in a way) that affects the id
var subSchema = mongoose.Schema({
//your subschema content
},{ _id : false });
Stop Mongoose from creating _id property for sub-document array items
Or I would say, when you create a character assign it a custom id from the start, that way it will retain that id throughout.
I'm leaving this question open as I would still like to see a simpler approach. But for now, I did find one easy alternative solution for this issue which I'm will be using for some time now until I find a more direct approach.
In short - Deep merge the new object in the old object using lodash and then use the new merged object to set field value.
For example, let's update the character Raghu from my question document:-
First install lodash(Required for deep merging objects) using npm:
$ npm i -g npm
$ npm i --save lodash
Import lodash:
const _ = require("lodash");
Now update the character Raghu like this:-
const newCharacterObj = {
age: "26",
name: "Dr. Raghu",
};
Drama.findById(
{ _id: req.drama._id, "characters._id": characterId },
"characters.$",
function(err, dramaDocWithSpecificCharacter) {
console.log(dramaDocWithSpecificCharacter);
// ↓↓↓ console would log ↓↓↓
// {
// "_id" : ObjectId("619d44d2ec2ca20ca0404b5a"),
// "characters" : [
// {
// "_id" : ObjectId("619fe1d53810a130207a409d"),
// "age" : "25",
// "name" : "Raghu",
// }
// ],
// }
const oldCharacterObj = dramaDocWithSpecificCharacter.characters[0];
const mergedCharacterObjs = _.merge(oldCharacterObj, newCharacterObj);
// _.merge() returns a deep merged object
console.log(mergedCharacterObjs);
// ↓↓↓ console would log ↓↓↓
// {
// _id: 619fe1d53810a130207a409d,
// age: "26",
// name: "Dr. Raghu",
// };
Drama.updateOne(
{ _id: req.drama._id, "characters._id": characterId },
{
$set: {
"characters.$": mergedCharacterObjs,
},
},
function(err, foundlist) {
if (err) {
console.log(err);
} else {
console.log("Update completed");
}
}
);
}
);
// req.drama._id is ObjectId("619d44d2ec2ca20ca0404b5a")
// characterId is ObjectId("619fe1d53810a130207a409d")
Note: We can also use the native Object.assign() or … (spread operator) to merge objects but the downside of it is that it doesn’t merge nested objects which could cause issues if you later decide to add nested objects without making changes for deep merge.
You can pass your payload or request body like this if we provide _id it will prevent update to nested document
"characters" : [
{
"_id" : "619fdac5a03c8b10d0b8b13c",
"age" : "updated value",
"name" : "updated value",
}, {
"_id" : "619fe1d53810a130207a409d",
"age" : "updated value",
"name" : "updated value",
}, {
"_id" : "619fe1d53810a130207a502v",
"age" : "updated value",
"name" : "updated value",
}
],
It works for me for bulk update in array object

Unable to update mongodb document with nested object property from node api

I have the following mongodb document:
{
"_id" : ObjectId("5ee95b41ca023a3deb252ef2"),
"uid" : "jdoe",
"name" : "John Doe",
"employee_hire_date" : "2012-06-20",
"three_month_review_target" : "2012-09-20",
"six_month_review_target" : "2012-12-20",
"three_month_review_status" : {
"is_scheduled" : null,
"is_team_member_emailed" : null,
"is_review_executed" : null,
},
"six_month_review_status" : {
"is_scheduled" : null,
"is_team_member_emailed" : null,
"is_review_executed" : null,
}
}
I would like to update the three_month_review_status.is_scheduled nested property to true. I am using a put request to accomplish this:
const mongoose = require('mongoose');
const Reviews = require('../modules/reviews/models/reviews');
module.exports = (app) => {
app.put('/api/reviews/isScheduled', async (req, res) => {
console.log('body', req.body)
console.log('uid', req.body.uid)
console.log('is_scheduled', req.body.three_month_review_status.is_scheduled)
Reviews.findOneAndUpdate( { 'uid': req.body.uid }, { $set: { 'three_month_review_status.is_scheduled': req.body.is_scheduled }}, (err, result) => {
if (err) {
console.log('error', err)
}
else {
console.log('updated', result);
res.status(200).send(result);
}
} )
});
}
To test this, I execute this PUT request through Postman with the following request body:
{
"uid": "jdoe",
"three_month_review_status": {
"is_scheduled": "true"
}
}
However, when the request gets executed, the other two nested objects are removed and is_scheduled remains null. This is the document after the request is executed:
{
"_id" : ObjectId("5ee95b41ca023a3deb252ef2"),
"uid" : "jdoe",
"name" : "John Doe",
"employee_hire_date" : "2012-06-20",
"three_month_review_target" : "2012-09-20",
"six_month_review_target" : "2012-12-20",
"three_month_review_status" : {
"is_scheduled" : null
},
"six_month_review_status" : {
"is_scheduled" : null,
"is_team_member_emailed" : null,
"is_review_executed" : null,
}
}
What am I doing wrong? Here is my reviewsSchema for more context:
const { Schema, model } = require('mongoose');
const reviewsSchema = new Schema({
uid: String,
name: String,
employee_hire_date: String,
three_month_review_target: String,
six_month_review_target: String,
three_month_review_status: {
is_scheduled: Boolean,
is_team_member_emailed: Boolean,
is_review_executed: Boolean,
},
six_month_review_status: {
is_scheduled: Boolean,
is_team_member_emailed: Boolean,
is_review_executed: Boolean,
},
})
const Reviews = model('review', reviewsSchema);
module.exports = Reviews;
In Mongoose you don't need to specify the $set. Also based on the sample JSON that you send from the postman instead of req.body.is_scheduled you need to provide req.body.three_month_review_status.is_scheduled in the query. Also, need to add {new: true} if you want the findOneAndUpdate to return the updated document
So you can update the query like
Reviews.findOneAndUpdate(
{ uid: req.body.uid },
{
"three_month_review_status.is_scheduled":
req.body.three_month_review_status.is_scheduled,
},
{ new: true },
(err, result) => {
if (err) {
console.log("error", err);
} else {
console.log("updated", result);
res.status(200).send(result);
}
}
);

Finding max field value in mongodb using node

I am new in mongodb and node. I am trying to find the max value for a field (userId). But it returns nothing.
My code is
EventSchema.static("createUser",function(event,user,callback){
var That = this;
var max_usr_Id = '';
async.waterfall([
function(callback) {
That.find({"userId" : {"$ne" : ""}, "$and" : [{"userId" : {"$exists" : 1}}]}).sort({"_id" : -1}).limit(1).select("userId").exec(function(err, doc)
{
if(err)
{
console.log('User ID ERROR-');
callback({error:err,message:"Error getting max User ID"});
}else {
console.log('User ID-');
console.log(doc.userId);
max_usr_Id = doc.userId;
console.log(max_usr_Id);
}
});
console.log(max_usr_Id);
},
});
For some reason the control doesn't go inside the find function. When I try the following query in mongodb shell it works.
db.users.find({
"userId" : {
"$ne" : ""
},
"$and" : [
{
"userId" : {
"$exists" : true
}
}
]
}).sort({
"_id" : -1.0
}).limit(1);
Any help is highly appreciated. Thanks in advance.
The $and is not used in the proper way, try with:
That.find({ $and: [
{ "userId": { $ne: "" } },
{ "userId": { $exists: true } }
] }).sort( ...
Take a look at the $and documentation.
Edit
After seen the comments, the problem must be in the way the logging is made. You need to call toArray to get a collection, and then iterate over it (with forEach for instance):
...find( ... ).toArray(function(err, docs) {
// Print each document returned
docs.forEach(function(doc) {
console.log(doc.userId);
});
});

mongodb deep update - mongoose .id() causing performance issue

mongoose level collection schema
{
sublevel: [{
"deeplevel": [{
}],
"deeplevel2": [{
}],
}]
}
//routes.js
dlDoc = { "dl1": "dl1" };
db.levels.update({ _id: ObjectId(levelId), "sublevel._id": ObjectId(sublevelId) }, { $push: { "sublevel.$.deeplevel1": dlDoc } }, function (err, updatedDoc) {
if (updatedDoc) {
res.json({ "status": 1 });
res.end();
//calling external apis to update more
result = externalApiResult();
db.levels.findById(level._id, 'sublevel._id sublevel.deeplevel1', function (err, levelFound) {
levelFound.sublevel.id(sublevelId).deeplevel.id(dlDoc._id)['result'] = result;
levelFound.save(function (err, savedDoc) {
});
})
}
});
I need to create and update the level collection's deeplevel1. in my case, the deeplevel1 will be inserted more than 2000 sub docs per day. when i want to update using mongoose .id(deepLevelId) function it is causing me performance issues in the server. is there any way to find the position of deeplevel document inserted once i update the level collection?. so that i can use the position in the update query. And please tell me a best way to update my deeplevel subdocuments without causing performance issues and works fast. thanks in advance.
db.collection.findOne() will be like this.
{
"_id" : ObjectId("563b35d1f07cc9d80a26436b"),
"name":"name",
sublevel:[{
"_id" : ObjectId("569bede3c717b670097519c7"),
"name" : "name",
"deeplevel2" : [{
"_id" : ObjectId("569c559329cc880c18989349"),
"logTime" : new Date("1/18/2016 03:30:48"),
"areaId" : ObjectId("568a6129de552e7dba98d547"),
}, {
"_id" : ObjectId("569c561929cc880c18989354"),
"logTime" : new Date("1/18/2016 03:30:48"),
"areaId" : ObjectId("568a6129de552e7dba98d547"),
}, {
"_id" : ObjectId("569c5945626ffb680e4512e9"),
"logTime" : new Date("1/18/2016 03:30:48"),
"areaId" : ObjectId("568a6129de552e7dba98d547"),
}, {
"_id" : ObjectId("569c594d626ffb680e4512eb"),
"logTime" : new Date("1/18/2016 03:30:48"),
"areaId" : ObjectId("568a6129de552e7dba98d547"),
}
]
}]
}

Fetch sub-document Mongodb only match with criteria

I have data in mongodb like this:
{
"_id" : ObjectId("55a12bf6ea1956ef37fe4247"),
"tempat_lahir" : "Paris",
"tanggal_lahir" : ISODate("1985-07-10T17:00:00.000Z"),
"gender" : true,
"family" : [
{
"nama" : "Robert Deniro",
"tempat_lahir" : "Bandung",
"tanggal_lahir" : ISODate("2015-07-09T17:00:00.000Z"),
"pekerjaan" : "IRT",
"hubungan" : "XXX",
"tanggungan" : false,
"_id" : ObjectId("55a180f398c9925299cb6e90"),
"meta" : {
"created_at" : ISODate("2015-07-11T20:59:25.242Z"),
"created_ip" : "127.0.0.1",
"modified_at" : ISODate("2015-07-12T15:54:39.682Z"),
"modified_ip" : "127.0.0.1"
}
},
{
"nama" : "Josh Groban",
"tempat_lahir" : "Jakarta",
"tanggal_lahir" : ISODate("2015-06-30T17:00:00.000Z"),
"pekerjaan" : "Balita",
"hubungan" : "Lain-Lain",
"tanggungan" : true,
"_id" : ObjectId("55a29293c65b144716ca65b2"),
"meta" : {
"created_at" : ISODate("2015-07-12T16:15:15.675Z"),
"created_ip" : "127.0.0.1"
}
}
]
}
when i try to find data in sub-document, with this code:
person.findOne({ _id: req.params.person, {'family.nama': new RegExp('robert', 'gi') }}, function(err, data){
// render code here
});
It show all data in Family Data,
Can we fetch or display a data only match with criteria/keyword, for example only "Robert Deniro" row
Thank You
In 'regular' MongoDB, you can use the $ operator for that. I'm not sure if it works with Mongoose, but it's worth a try:
person.findOne({
_id : req.params.person,
'family.nama' : new RegExp('robert', 'gi')
}, {
// Only include the subdocument(s) that matched the query.
'family.$' : 1
}, function(err, data){
// render code here
});
If you need any of the properties from the parent document (tempat_lahir, tanggal_lahir or gender; _id will always be included), you need to add them to the projection object explicitly.
One caveat: the $ operator will only return the first matching document from the array. If you need it to return multiple documents, you can't use this method and (AFAIK) have to postprocess the results after they are returned from the database.
It solved with this code:
var options = {
family: {
$elemMatch: { nama: req.query.keyword }
},
};
person.findOne({ _id: req.params.person, 'family.nama': keyword }, options, function(err, data){
//render code here
});
Thanks to #hassansin & #robertklep

Resources