Mongoose findOneAndUpdate on array of subdocuments - javascript

I'm trying to replace an array of sub-documents with a new copy of the array.
Something like...
var products = productUrlsData; //new array of documents
var srid = the_correct_id;
StoreRequest.findOneAndUpdate({_id: srid}, {$set: {products: products}}, {returnNewDocument : true}).then(function(sr) {
return res.json({ sr: sr}); //is not modified
}).catch(function(err) {
return res.json({err: err});
})
The products var has the correct modifications, but the returned object, as well as the document in the db, are not being modified. Is this not the correct way to replace a field which is an array of subdocuments? If not, what is?

I am a bit late to the party plus I am really in a hurry -- but should be:
StoreRequest.updateOne(
{ _id: srid },
{ $set: { 'products.$': products }},
{ new: true });
I couldn't make it work with findOneAndUpdate but the above does work.

Related

Mongo / Mongoose - Push object into document property array on condition

I have a document stored on mongo that, amongst others, contains a property type of an array with a bunch of objects inside. I am trying to push an object to that array. However each object that gets pushed to into the array contains a date object. How I need it to work is if an object with that date already exists then dont push the new object into the array.
I'm been playing with it for a while, trying to run update and elemMatch queries etc, but I can't figure it out. I have a long draw out version below, as you can see I'm making 2 separate requests to the database, can someone help me reduce this to something simpler?
UserModel.findById(req.user._id, (err, doc) => {
if (err) {
return res.sendStatus(401);
}
const dateExists = doc.entries.find((entry) => entry.date === date);
if (dateExists) {
res.sendStatus(401);
} else {
UserModel.findByIdAndUpdate(
req.user._id,
{
$push: {
entries: {
date,
memo,
},
},
},
{ safe: true, upsert: true, new: true },
(err, doc) => (err ? res.sendStatus(401) : res.sendStatus(200))
);
}
});
Thanks.
db.users.updateOne({
_id: req.user._id,
"entries.date": date,
},
{
$push: {
entries: {date,memo},
}
})
https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/index.html

Javascript object not updating with Array.Map()

I have an Express API in which I have the following Mongoose query that extracts posts from the database and then I want to convert the timestamp from the database (a Date() object) into a relative time string.
As you can see, I am trying to add a time property that has this string as a value to the posts object using Array.Map.
That seems to work, because logging items[0].time in the console returns the proper value (see comment in the cose).
HOWEVER! when sending the object back with res.json, the time property is not in it.
I thought this might be a client-side cache issue, but when adding another value in res.json, the new value gets sent along with the posts just fine.
Post.find({}, 'author text timestamp')
.sort({ _id: -1 })
.populate({ path: 'author', select: 'username' })
.exec(function(error, posts) {
if (error) {
console.error(error)
}
items = posts.map(function(item) {
item.time = moment(item.timestamp).fromNow()
return item
})
console.log('Relative date:' + items[0].time) // This logs: "Relative date:an hour ago"
res.json({
posts: items
})
/*
Response:
posts: {
0: {
author: {_id: "5c98f40f793edf61bcc94b4d", username: "Admin"},
text: "Why",
timestamp: "2019-04-04T15:46:36.142Z",
_id: "5ca626dc45734a2612acbcd2"
}
}
*/
})
Is this a server-related cache issue or something unique to Mongoose objects that I don't know about?
Thanks in advance for the help.
I was able to solve this using Post.find().lean() in my code.

Mongoose: Add more items to existing object

Using Mongoose, How can I add more items to an object without replacing existing ones?
User.findOneAndUpdate(
{ userId: 0 },
{ userObjects: { newItem: value } }
);
The problem with above code is that it clears whatever was there before and replaces it with newItem when I wanted it just to add another item to userObjects(Like push function for javascript arrays).
Use dot notation to specify the field to update/add particular fields in an embedded document.
User.findOneAndUpdate(
{ userId: 0 },
{ "userObjects.newerItem": newervalue } }
);
or
User.findOneAndUpdate(
{ userId: 0 },
{ "$set":{"userObjects.newerItem": newervalue } }
);
or Use $mergeObjects aggregation operator to update the existing obj by passing new objects
User.findOneAndUpdate(
{"userId":0},
[{"$set":{
"userObjects":{
"$mergeObjects":[
"$userObjects",
{"newerItem":"newervalue","newestItem":"newestvalue"}
]
}
}}]
)
According to your question, i am guessing userObjects is an array.
You can try $push to insert items into the array.
User.findOneAndUpdate(
{ userId: 0 },
{ $push : {"userObjects": { newItem: value } }},
{safe :true , upsert : true},function(err,model)
{
...
});
For more info, read MongoDB $push reference.
Hope it helps you. If you had provided the schema, i could have helped better.
Just create new collection called UserObjects and do something like this.
UserObject.Insert({ userId: 0, newItem: value }, function(err,newObject){
});
Whenever you want to get these user objects from a user then you can do it using monogoose's query population to populate parent objects with related data in other collections. If not, then your best bet is to just make the userObjects an array.

Mongodb save into nested object?

I can't get my req.body inserted into my mongodb collection.
I have this route that triggers the add method and inside I am trying to figure out a query to save the req.body into a nested collection array
router.post('/api/teams/:tid/players', player.add);
add: function(req, res) {
var newPlayer = new models.Team({ _id: req.params.tid }, req.body);
newPlayer.save(function(err, player) {
if (err) {
res.json({error: 'Error adding player.'});
} else {
console.log(req.body)
res.json(req.body);
}
});
}
Here is an example document
[
{
"team_name":"Bulls",
"_id":"5367bf0135635eb82d4ccf49",
"__v":0,
"players":[
{
"player_name":"Taj Gibson",
"_id":"5367bf0135635eb82d4ccf4b"
},
{
"player_name":"Kirk Hinrich",
"_id":"5367bf0135635eb82d4ccf4a"
}
]
}
]
I can't figure out how to insert/save the POST req.body which is something like
{
"player_name":"Derrick"
}
So that that the new req.body is now added into the players object array.
My question is how do I set the mongodb/mongoose query to handle this?
P.S I am obviously getting the error message because I don't think the query is valid, but it's just kind of an idea what I am trying to do.
Something like this is more suitable, still doesn't work but its a better example I guess
var newPlayer = new models.Team({ _id: req.params.tid }, { players: req.body });
If you created a Team model in Mongoose then you could call the in-built method findOneAndUpdate:
Team.findOneAndUpdate({ _id: req.params.tid },
{ $addToSet: { players: req.body} },
function(err, doc){
console.log(doc);
});
You could do findOne, update, and then save, but the above is more straightforward. $addToSet will only add if the particular update in question doesn't already exist in the array. You can also use $push.
The above does depend to an extent on how you have configured your model and if indeed you are using Mongoose (but obviously you asked how it could be done in Mongoose so I've provided that as a possible solution).
The document for $addToSet is at http://docs.mongodb.org/manual/reference/operator/update/addToSet/ with the relevant operation as follows:
db.collection.update( <query>, { $addToSet: { <field>: <value> } } );

Return updated collection with Mongoose

I work with nodejs/express/mongoose/angularjs. I'd like to update a collection named Lists which has several properties, one of which is an array of items. In the following code, I'm pushing a new task items in the items array. Everything works fine, however the update function does not sends back the updated collection, then I must perform another query on the database. Is there a more efficient way to do this ?
The nodejs/express code :
exports.addTaskToList = function(req, res) {
var listId = req.params.Id;
var taskId = req.params.TaskId;
Lists.update({_id: listId}, {$push: {items: taskId}}, {safe:true, upsert: true}, function(err, result){
if(err) {
console.log('Error updating todo list. ' + err);
}
else{
console.log(result + ' todo list entry updated - New task added');
Lists.findById(listId).populate('items').exec(function (err, updatedEntry) {
if (err) {
console.log('Unable to retrieve todo list entry.');
}
res.send(JSON.stringify(updatedEntry));
});
}
});
};
Furthermore, the array items is an array of ObjectIds. Those items are in a separate schema so in a separate collection. Is it possible to push the whole object and not only its _id so that there is not another collection created ?
use findOneAndUpdate() method and in query parameter use option as { "new": true}
return this.sessionModel
.findOneAndUpdate({user_id: data.user_id}, {$set:{session_id: suuid}}, { "new": true})
.exec()
.then(data=>{
return {
sid: data.session_id
}
})
The update method doesn't return the updated document:
However, if we don't need the document returned in our application and
merely want to update a property in the database directly,
Model#update is right for us.
If you need to update and return the document, please consider one of the following options:
Traditional approach:
Lists.findById(listId, function(err, list) {
if (err) {
...
} else {
list.items.push(taskId)
list.save(function(err, list) {
...
});
}
});
Shorter approach:
Lists.findByIdAndUpdate(listId, {$push: {items: taskId}}, function(err, list) {
...
});
Regarding your last question:
Is it possible to push the whole object and not only its _id so that
there is not another collection created ?
The answer is yes. You can store sub-documents within documents quite easily with Mongoose (documentation on sub-documents here). By changing your schema a little, you can just push your whole item object (not just item _id) into an array of items defined in your List schema. But you'll need to modify your schema, for example:
var itemSchema = new Schema({
// Your Item schema goes here
task: 'string' // For example
});
var listSchema = new Schema({
// Your list schema goes here
listName: String, // For example...
items: [itemSchema] // Finally include an array of items
});
By adding an item object to the items property of a list, and then saving that list - your new item will be persisted to the List collection. For example,
var list = new List({
listName: "Things to do"
});
list.items.push({
task: "Mow the lawn"
});
list.save(function(error, result) {
if (error) // Handle error
console.log(result.list) // Will contain your item instance
});
So when you load your list, the items property will come pre-populated with your array of items.
This is because Items will no longer persist it a separate collection. It will be persisted to the List collection as a sub-document of a List.

Categories

Resources