Using Mongo findOneAndUpdate, I am trying to update just some fields in an object from array of objects.
My object:
mainObject:{
_id: '123',
array:[
{title:'title' , name:'name', keep:'keep'},
{title:'title', keep:'keep'},
]
}
I want to change title and name for the first object in array, and keep the keep field unchanged.
This is my closest approach using Positional Operator:
// here i set dynamic arguments for query update
// sometimes i need to update only one field, sometime i need to update more fields
// also, is there a better way to do this?
let title
let name
if (args.title) {
title = { title: args.title };
}
if (args.name) {
name= { name: args.name};
}
db.Test.findOneAndUpdate(
{ _id: args.id, 'mainObject.array.title': args.title},
{
$set: {
'mainObject.array.$[]': {
...title,
...name
}
}
}
)
this problem is that it replace the whole object, the result is:
mainObject:{
array:[
{title:'changed' , name:'changed'}, //without keep... :(
{title:'title', keep:'keep'},
]
}
Should I use aggregation framework for this?
It has to be like this :
db.test.findOneAndUpdate({'mainObject.array.title': 'title'},
{$set : {'mainObject.array.$.title':'changed','mainObject.array.$.name': 'changed'}})
From your query, $ will update the first found element in array that matches the filter query, if you've multiple elements/objects in array array then you can use $[] to update all of those, let's see your query :
'mainObject.array.$[]': {
...title,
...name
}
Major issue with above query is that it will update all the objects in array array that match the filter with below object :
{
...title,
...name
}
So, it a kind of replace entire object. Instead use . notation to update particular values.
Related
I have a range of documents
{
_id: ObjectId("5e388da4df54cb8efb47e61b"),
userId:'test_user'
productId:'product_6_id'
recommendations:{
_id:123
rankedList:[
0:{id:ObjectId('product_5_id'),Name:'Product_5'},
1:{id:ObjectId('product_6_id'),Name:'Product_6'},
2:{id:ObjectId('product_3_id'),Name:'Product_3'}],
Date:'2020-02-25T05:03:55.439+00:00'
}
},
{
_id: ObjectId("5e388da4df54cb8efb47e62b"),
userId:'test_user1'
productId:'product_3_id'
recommendations:{
_id:123
rankedList:[
0:{id:ObjectId('product_1_id'),Name:'Product_1'},
1:{id:ObjectId('product_5_id'),Name:'Product_5'},
2:{id:ObjectId('product_3_id'),Name:'Product_3'}],
Date:'2020-02-25T05:03:55.439+00:00'
}
}
and I need to find each time the position of productId within the Array of objects rankedList.
Thus here the answer would be positionIndex=1 for first doc and positionIndex=2 for second document.
I am quite confused with $indexOfArray and how I should use it here with aggregate.
Yes, you need $indexOfArray. The tricky part is that recommendations.rankedList is an array of objects however MongoDB allows you to use following expression:
$recommendations.rankedList.id
which evaluates to a list of strings, ['product_5_id', 'product_6_id', 'product_3_id'] in this case so your code can look like this:
db.collection.aggregate([
{
$project: {
index: {
$indexOfArray: [ "$recommendations.rankedList.id", "$productId" ]
}
}
}
])
Mongo Playground
found a lot of questions like these here, but not an answer.
Problem
Lets say I have the following mongoose schema:
const mySchema = new mongoose.Schema({
sanePeoplesField: String,
comments: [
normalStuff: {type: Date, default: Date.now},
damNestedAgain: [String]
]
})
So to recap, damNested array is inside the comments array on the schema.
If I was lucky and wanted to change normalStuff (obj inside an array), I'd do this:
mySchema.findOneAndUpdate({"comments._id": req.body.commentId},
{
$push:
{
comments: { normalStuff: 12122020 } }
}
})
This would've updated normalStuff with a new value.
However, I need to update a field in damNestedAgain, but don't know how to reach it!
Question
How to update the nested array of a nested array, damNestedAgain, in my example?
mySchema.findOneAndUpdate({"comments._id": req.body.commentId},
{
$push:
{
"comments.$.damNestedAgain": req.body.commentId
}
})
That has done the trick, thanks.
Lets say I have an object in ES such as:
{
name: "calendar";
events: [
{
birthday: "1992-10-09",
graduation: "2018-06-15",
wedding: "2016-12-12"
}
]
}
Is there a way I can query over the events array to find an element in the events array that is passed the current date.
So far I have:
GET /index/type/_search
{
"query": {
"range" : {
"events" : {
"gte" : "now"
}
}
}
}
but that does not iterate over each object in the array and return the name of the event. For this scenario it should return the object graduation: "2018-06-15". Thanks for the help!
You can use Nested datatypes to store nested documents inside parent document.
And to query back the Nested types you can use Nested Query.
Hi guys so I'm doing meteor mongo db, I use findAndModify package
Ips.findAndModify({
//Find the desired document based on specified criteria
query: {
"ipAdr": clientIp,
connections: {
$elemMatch: {
connID: clientConnId
}
}
},
//Update only the elements of the array where the specified criteria matches
update: {
$push: {
'connections': {
vid: result.data.vid,
firstName: result.data.properties.firstname.value,
lastName: result.data.properties.lastname.value
}
}
}); //Ips.findAndModify
So I find the element that I need however my info is being pushed to the whole connections array, but I want to push my info into that specific element. What should I do here? I tried
$push: {
'connections.$': {
vid: result.data.vid,
but it gives error.
Please help.
You don't need to use the $push operator here as it adds a new element to array, instead you need to modify an element that is already in the array, try the $set operator to update as follows:
update: {
$set: {
'connections.$.vid': result.data.vid,
'connections.$.firstName': result.data.properties.firstname.value,
'connections.$.lastName': result.data.properties.lastname.value
}
}
Take into account that this way you will change only one element of the array that satisfies the condition from the $elemMatch statement.
Example document:
{
"_id" : "5fTTdZhhLkFXpKvPY",
"name" : "example",
"usersActivities" : [
{
"userId" : "kHaM8hL3E3As7zkc5",
"startDate" : ISODate("2015-06-01T00:00:00.000Z"),
"endDate" : ISODate("2015-06-01T00:00:00.000Z")
}
]
}
I'm new in mongoDB and I read other questions about updating nested array and I can't do it properly. What I want to do is to change startDate and endDate for user with given userId. My problem is that it always pushes new object to array instead of changing object with given userId.
Activity.update(
_id: activityId, usersActivities: {
$elemMatch: {
userId: Meteor.userId()
}
}},
{
$push: {
'usersActivities.$.startDate': start,
'usersActivities.$.endDate': end
}
}
);
I will be really glad of help.
So the first thing to say here is the $elemMatch is not required in your case as you only want to match on a single array property. You use that operator when you need "two or more" properties from the same array element to match your conditions. Otherwise you just use "dot notation" as a standard.
The second case here is with $push, where that particular operator means to "add" elements to the array. In your case you just want to "update" so the correct operator here is $set:
Activity.update(
{ "_id": activityId, "usersActivities.userId": Meteor.userId() },
{
"$set": {
'usersActivities.$.startDate': start,
'usersActivities.$.endDate': end
}
}
)
So the positional $ operator here is what matches the "found index" from the array element and allows the $set operator to "change" the elements matched at that "position".
"What if Meteor.userId() does not exist, how to insert the whole of object with userID, startDate and endDate? – justdiehard Jun 14 at 20:20"
If you try to put new, you should take a look at Meteor Accounts package, there are methods like
Accounts.createUser(YOU_USER_SCHEME)