How to update the details in an array on post in MongoDB? - node.js

Although its printing the 'success' in console but i am unable to see the changes after clicking on post update.
User.update( { email:req.user.email },
{ $set: {
"Addtasks.$[].topic": req.body.topic,
"Addtasks.$[].words": req.body.words,
"Addtasks.$[].keywords": req.body.keywords,
"Addtasks.$[].website": req.body.website,
"Addtasks.$[].otherdetails": req.body.otherdetails,
"Addtasks.$[].exampleRadios": req.body.exampleRadios
} },function (error, success) {
if (error) {
console.log(error);
} else {
res.redirect('/status');
console.log('success');
}
} )
My json array file:
[
{
"Date" : "Mon Aug 03 2020 03:30:17 GMT+0530 (India Standard Time)",
"exampleRadios" : "option1",
"otherdetails" : "haha great!",
"website" : "nmbn.com",
"keywords" : "anxiety disorders for children, anxiety disorders for adults",
"words" : 456,
"topic" : "How to fight anxiety",
"_id" : ObjectId("5f273771ddff850558b1e049")
}
]

Did you checked the db if it's updated? Because if you using native mongodriver, update will not return document itself, you have to use findOneAndUpdate. Second thing, findOneAndUpdate will not return updated document, but old one (dunno why they configured it like this), you have to use options = { returnOriginal: false } (default is true).

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

How to avoid creating object inside object and push the elements directly into an array in express using mongoose?

filesArray is the array of objects means contain all files upload datas like path, filename etc. So I am just fetching the path and filename and pushing it into another array called Bigpaths2. So while I am pushing Bigpaths2 into the Addtasks array's array Bigpaths4clients it get pushed successfully but by creating another array inside Bigpaths4clients and then get pushed in form of objects.
But I don't want that. I want to prevent that array creation. I just want all the paths object inside Bigpaths2 should directly be pushed inside Bigpaths4clients array creating single objects. I have attached an image as well in last to conclude which i dont want. Check json format as well thanks!
var Bigpaths2 = [], paths;
filesArray.forEach(element => {
paths = {
"path": element.path,
"name": element.filename
};
Bigpaths2.push(paths);
})
User.findOneAndUpdate(
{ 'Addtasks.commonID':cid },
{ $push: { 'Addtasks.$.Bigpaths4Clients': Bigpaths2 } },
function (error, WriterData) {
if (error) {
console.log(error);
}
else
{
console.log("success");
}
}
)
User schema:
[
{
"assignee" : "Charlotte Miles",
"displayLock" : "none",
"displayDelete" : "inline",
"commonID" : "x0yosfn1uz",
"status" : "Approved by Admin",
"Date" : "Fri Sep 04 2020 15:36:11 GMT+0530 (India Standard Time)",
"exampleRadios" : "option1",
"otherdetails" : "haha great!",
"website" : "asad.com",
"keywords" : "article importance, article generation, article quality",
"words" : 12345,
"topic" : "How article is generated?",
"_id" : ObjectId("5f5211b29dc68d04244a6774"),
"Bigpaths4Clients" : [
[
{
"name" : "api-ms-win-core-errorhandling-l1-1-0.dll",
"path" : "public\\files\\api-ms-win-core-errorhandling-l1-1-0.dll"
}
]
],
"Bigpaths" : [
{
"path" : "public\\files\\api-ms-win-core-errorhandling-l1-1-0.dll",
"name" : "api-ms-win-core-errorhandling-l1-1-0.dll"
}
]
}
]
User.findOneAndUpdate(
{ 'Addtasks.commonID':cid },
{ $push: { 'Addtasks.$.Bigpaths4Clients': { $each: Bigpaths2 } } },
function (error, WriterData) {
if (error) {
console.log(error);
}
else
{
console.log("success");
}
}
)
$each operator is used to append multiple values to the array field.
In your case, MongoDB considering the whole Bigpaths2 array as a single element to append to Bigpaths4Clients array
here's the official dock link https://docs.mongodb.com/manual/reference/operator/update/push/#append-multiple-values-to-an-array

angular/express api/mongodb update issue

working with a full MEAN stack.
trying to write data to a "notes" array in my mongodb document id #1.
mongo document:
> db.contacts.find().pretty()
{
"_id" : ObjectId("5a294af85e96746421bf35f1"),
"id" : 1,
"type" : "dealer",
"name" : "ken yoder",
"company" : "kens sales",
"phone" : "817-403-9767",
"notes" : [
{
"date" : "Thu Dec 07 2017 08:15:37 GMT-0600 (CST)",
"by" : "#me",
"note" : "this is a note"
},
{
"date" : "Thu Dec 07 2017 08:16:31 GMT-0600 (CST)",
"by" : "#donny",
"note" : "bla bla bla mumford and sons"
},
{
"date" : "Thu Dec 07 2017 08:34:03 GMT-0600 (CST)",
"by" : "#ken",
"note" : "test with another note"
},
{
"date" : "Thu Dec 07 2017 08:34:29 GMT-0600 (CST)",
"by" : "#ken",
"note" : "test with another notey note note"
}
],
"setNotes" : {
"date" : "Thu Dec 07 2017 10:52:09 GMT-0600 (CST)",
"by" : "#kale",
"note" : "hhsdihufiudhsiuhdshuifds"
}
}
express code:
app.get('/newNote/:noteFor/:noteCount/:noteBy/:note/', function (req, res) {
var setNotes = "notes."+req.params.noteCount;
db.collection('contacts').update({ id:req.params.noteFor }, { $set: { setNotes : {date: Date(), by: req.params.noteBy, note: req.params.note} }}, function(err, res) {
if (err) throw err;
console.log("notefor: "+req.params.noteFor+" noteCount: "+setNotes+" noteBy: "+req.params.noteBy+" note: "+req.params.note);
console.log(res.result.nModified + " for " + req.params.noteFor + " updated");
});
});
if i run this code as it sits, i get nothing, no insert, no errors.
- if i change the update id from "req.params.id" to "1", i get an insert but...
- instead of using my "setNotes" variable (which outputs "notes.4") for the $set identifier, it created a new object called "setNotes".
API URL: /newNote/1/4/#kale/this is a note test
This will just add a new document everytime to notes array:
db.collection('contacts').update({ id:req.params.noteFor }, {
$push: {
notes : {date: Date(), by: req.params.noteBy, note: req.params.note}
}
}, function(err, res) {
//code
}
first read express api basics, http://expressjs.com/en/4x/api.html. from question there is noting in req.params.id , instead of id req.params contain four keys (noteFor, noteCount, noteBy and note ). also you override res varible by result of query notice function(err, res) {.........
db.collection('contacts').update(
{ id:req.params.id },
{ $set:
{ setNotes : {date: Date(), by: req.params.noteBy, note: req.params.note} }
},
{
// if noting found then stop create new document with values of $set
upsert:false
// result should be updated document
new:true
},
function(err, result) {
console.log(err, result)
})

Unable to push an item into a MongoDB array within the document while using Waterline

I'm struggling with an update call that just doesn't seem to work for some reason. For some quick context, we have a Node.js application running on Sails.js with Waterline ORM.
As per my package.json file, here are the versions I am using:
connect-mongo: ^1.3.2
mongodb: ^2.2.29
sails: ~0.12.4
sails-mongo: ^0.12.3
I have a collection called "products" and each product looks like this in the database:
{
"_id" : ObjectId("59d5f12025423dc0261c911d"),
"category" : ObjectId("59a9bcf984d756998eaa22e5"),
"status" : "pendingReview",
"isDeleted" : false,
"events" : [
{
"when" : 1507193120,
"actor" : "56cc0f76e1a25cde0d2c15ab",
"action" : "Submitted product",
"note" : "Jeff added this product. It is awaiting review."
}
],
"productId" : "171005-00000",
"createdAt" : ISODate("2017-10-05T08:45:20.538Z"),
"updatedAt" : ISODate("2017-10-05T08:45:20.538Z")
}
I have a UI where a user can "approve" multiple products before they are displayed to website visitors. To do this, I want to just update multiple records by changing the status key to "approved" and adding an event in the events array of each document. The event must be in position 0 of the array. I am trying to update these records with the following code but it doesn't seem to work:
var moment = require('moment');
Products.native(function(error, collection) {
if (error) {
throw error;
}
collection.update(
{ _id: ['59d5f12025423dc0261c911d'] },
{
$set: {
status: 'approved',
$push: {
events: {
when: moment().unix(),
actor: req.body.userId,
action: 'Approved product',
note: req.body.userName + ' approved this product.'
}
}
}
},
{ multi: true },
function(error, count, status) {
if (error) {
sails.log.error(error);
return res.serverError('Database error. Reference ID: ' + req.referenceId);
}
return res.ok(count);
});
});
When I run this query, I don't get any error and when I check my database, the record has not been updated. I get the following data when I run the query:
{
"ok": 1,
"nModified": 0,
"n": 0
}
What's going on here? Why isn't getting updated? If I understand correctly, the query is able to find the document but it isn't getting updated. Is that correct? If yes, how do I resolve this? Thanks.
$push should be at the same level as $set. They are both operators...
This means you should change like this:
{
$set: {
status: 'approved'
},
$push: {
events: {
when: moment().unix(),
actor: req.body.userId,
action: 'Approved product',
note: req.body.userName + ' approved this product.'
}
}
}

mongodb query on nodeJS say cannot read property remove of 'null'

This is my entry in database in mongodb which is of type object in schema
"_id" : ObjectId("5539bed4b417d75d1fee5df7"),
"favMovies" : {
"alternate_ids" : {
"imdb" : "2820852"
},
"studio" : "Universal Pictures",
"abridged_directors" : [
{
"name" : "James Wan"
}
],
"abridged_cast" : [
{
"characters" : [
"Dominic Toretto"
],
"id" : "162652472",
"name" : "Vin Diesel"
},
{
"characters" : [
"Brian O'Conner"
],
"id" : "162654234",
"name" : "Paul Walker"
},
{
"characters" : [
"Louie Tran"
],
"id" : "162684066",
"name" : "Tony Jaa"
},
{
"characters" : [
"Deckard Shaw"
],
"id" : "162653720",
"name" : "Jason Statham"
},
{
"characters" : [
"Luke Hobbs"
],
"id" : "770893686",
"name" : "Dwayne \"The Rock\" Johnson"
}
],
"synopsis" : "Continuing the global exploits in the unstoppable franchise built on speed, Vin Diesel, Paul Walker and Dwayne Johnson lead the returning cast of Fast & Furious 7. James Wan directs this chapter of the hugely successful series that also welcomes back favorites Michelle Rodriguez, Jordana Brewster, Tyrese Gibson, Chris \"Ludacris\" Bridges, Elsa Pataky and Lucas Black. They are joined by international action stars new to the franchise including Jason Statham, Djimon Hounsou, Tony Jaa, Ronda Rousey and Kurt Russell.",
"ratings" : {
"audience_score" : 88,
"audience_rating" : "Upright",
"critics_score" : 82,
"critics_rating" : "Certified Fresh"
},
"release_dates" : {
"theater" : "2015-04-03"
},
"critics_consensus" : "",
"runtime" : 140,
"mpaa_rating" : "PG-13",
"genres" : [
"Mystery & Suspense",
"Action & Adventure"
],
"year" : 2015,
"title" : "Furious 7",
"id" : 771354922
},
"username" : "punk",
"__v" : 0
}
In my Node JS code I use the following query
app.delete('/favMovies/:user/:movid',function(req, res){
var user = req.params.user;
var mid = req.params.movid;
console.log(mid);
console.log(user);
MovModel.find({username:user,'favMovies.id':mid}, function (err, doc) {
doc.remove();
MovModel.find({username: user},function (err, data) {   
res.json(data);
});
});
});
In the above snippet mid is movie id. For the above entry in database mov
"id" : 771354922
and user is username but I am getting following error for my query which is working fine in mongo client.
/Users/pankajtripathi/Documents/ECLIPSE-FILES/MyProject/server.js:132
doc.remove();
^
TypeError: Cannot read property 'remove' of null
at /Users/pankajtripathi/Documents/ECLIPSE-FILES/MyProject/server.js:132:5
at /Users/pankajtripathi/Documents/ECLIPSE-FILES/MyProject/node_modules/mongoose/lib/query.js:1169:16
at /Users/pankajtripathi/Documents/ECLIPSE-FILES/MyProject/node_modules/mongoose/node_modules/kareem/index.js:103:16
at process._tickCallback (node.js:355:11)
You should use findOneAndRemove()
MovModel.findOneAndRemove({username:user,'favMovies.id':mid}, function (err, doc) {
if (err) console.log(err);
res.json(doc);
}
Finds a matching document, removes it, passing the found document (if
any) to the callback. Executes immediately if callback is passed.
I changed the query and its working fine now.
MovModel.findOneAndRemove({username:user,_id:mid}, function (err, doc) {
console.log(doc);
MovModel.find({username: user},function (err, data) {
res.json(data);
});
});

Resources