MongoDB push data to specific array element - arrays

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.

Related

Delete many items from array of documents in mongodb that match this value

I am trying to delete all documents from an array of documents that match this value but cannot figure it out,
This is my delete query that is not working, courses is the array I need to be in and code is the document I need to check to see its value for deletetion. So if courses.code == 123, then delete and keep going sort of thing.
result = await mongoClient.db(DB_NAME).collection("technologies").deleteMany({ 'courses': {$in: 'courses.code'} });
That is what it looks like in my collection.
"name": "Sass",
"description": "Sass (Syntactically awesome style sheets) is a preprocessor scripting language that is interpreted or compiled into Cascading Style Sheets (CSS).",
"difficulty":2,
"courses":[
{"code":"PROG2700","name":"Client Side Programming"},
{"code":"PROG3017","name":"Full Stack Programming"}
]
},
Any help would be great, thanks!
You can filter documents that contain the field you want to update
Do tests before updates on the original collection.
After some searches, I've found this method:
const filter = { }
db.collection.update(filter,
{
$pull: {
"courses": {
code: {
$in: [
"PROG3017",
"PROG2700"
]
}
}
}
},
{
multi: true
})
This pulls out any element in the array where the value of code is $in the array.

Mongo find position by id in an Array of Objects

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

How to update an object inside an array inside another array in a mongoose schema?

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.

Mongo update multiple fields of an object which is inside an array

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.

Meteor mongo updating nested array

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)

Resources