MongoDB : "unexpected token" error when trying to Update document field that is an array - arrays

I have a collection called Names with a document that looks like this:
{
"_id":33,
"listOfNames" : ["John", "Fred", "Andy"]
}
I am trying to do an update command that looks like the following:
db.Names.update{{}, {$set: {"listOfNames" : ["John", "Mary"]}, {multi:true})}
This fails with "unexpected token". What is the correct syntax to use when updating a field in a series of documents when the field is an array?

use this query
db.Names.update({},
{
$set: {"listOfNames":["John", "Mary"]},
}, { multi : true })
Anyway you put redundant { after update function, You should use (
And you put ) in wrong place

Related

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.

Updating a collection inside array of collections in MongoDB

I have a mongo collection workspaces in my MongoDB which consist of records that looks like as follows:
{
"_id" : ObjectId("58bdc4a13504f5ed743ad025"),
"name" : "My workspace",
"user_id" : ObjectId("58b6cf53988a874af070fd3b"),
"uploads" : [
{
"original" : "DE-20__450_GG_5002_N23_994__0136.tif"
},
{
"original" : "DE-20__450_GG_5002_N23_994__0134.png"
},
{
"original" : "DE-20__450_GG_5002_N23_994__0136.png"
},
{
"original" : "DE-20__450_GG_5002_N23_994__0134.tif"
}
]
}
Now my objective is that i want to append something in one of record of array uploads with the match criteria of original field value. For example i want to append "pseg" : "DE-20__450_GG_5002_N23_994__0136.pseg.tif" to the {"original" : "DE-20__450_GG_5002_N23_994__0136.tif"} collection in following way:
{
"_id" : ObjectId("58bdc4a13504f5ed743ad025"),
"name" : "Objective",
"user_id" : ObjectId("58b6cf53988a874af070fd3b"),
"uploads" : [
{
"original" : "DE-20__450_GG_5002_N23_994__0136.tif",
"pseg" : "DE-20__450_GG_5002_N23_994__0136.pseg.tif"
},
{
"original" : "DE-20__450_GG_5002_N23_994__0134.png"
},
{
"original" : "DE-20__450_GG_5002_N23_994__0136.png"
},
{
"original" : "DE-20__450_GG_5002_N23_994__0134.tif"
}
]
}
i tried using $elemMatch and then i added $addToSet in following way:
db.getCollection('workspaces').update({"_id": ObjectId("58bdc4a13504f5ed743ad025"),"uploads": {$elemMatch: {"original": "DE-20__450_GG_5002_N23_994__0136.tif"}}},{$addToSet:{"uploads.$": {"pseg" : "DE-20__450_GG_5002_N23_994__0136.pseg.tif"}}})
but it gives me following error:
Cannot apply $addToSet to a non-array field. Field named '0' has a non-array type object in the document _id: ObjectId('58bdc4a13504f5ed743ad025')
I think i crafted the query wrong can anyone tell me what is wrong and how can i solve it?
Sorry for my bad english :) hope you understood what i said.
Here is the correct syntax. You have to use $set with postional operator to reach the element.
db.getCollection('workspaces').update(
{"_id": ObjectId("58bdc4a13504f5ed743ad025"),"uploads": {$elemMatch: {"original": "DE-20__450_GG_5002_N23_994__0136.tif"}}},
{$set:{"uploads.$.pseg" : "DE-20__450_GG_5002_N23_994__0136.pseg.tif"}})
More information here https://docs.mongodb.com/manual/reference/operator/update/positional/#update-documents-in-an-array
You can simplify your query criteria. You don't need to use $elemMatch operator for single query condition. You can use dot notation.
db.getCollection('workspaces').update(
{"_id": ObjectId("58bdc4a13504f5ed743ad025"),"uploads.original": "DE-20__450_GG_5002_N23_994__0136.tif"},
{$set:{"uploads.$.pseg" : "DE-20__450_GG_5002_N23_994__0136.pseg.tif"}})
More information here
https://docs.mongodb.com/manual/reference/operator/query/elemMatch/#single-query-condition

Elasticsearch : Set the number of the elements of an array in a field

I'm trying to store the number of elements of an array into a field with an update. (updating the record with the count of the array).
Like for example
{
array = [ { "a" : "b" }, { "c" : "d" } ]
nb_elements = 2
}
I have tried an update with the following script
{
"script" : "ctx._source.nb_elements= ctx._source.array.values.length"
}
But it don't work.
I also tried :
{
"script" : "ctx._source.nb_elements = count",
"params" : {
"count" : ctx._source.array.values.length
}
}
But i wasn't more successfull.
Does anybody know if this is possible and if, how to do it ?
First of all you need to enable dynamic scripting by adding script.disable_dynamic: false to your config file.
Secondly, I'm supposing that you are using groovy (It's the default scripting language from 1.4).
Using the update api with this script should work:
{
"script": "ctx._source.nb_elements=ctx._source.array.size"
}

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)

Updating values in nested arrays in MongoDB

I found this answer https://stackoverflow.com/a/12636038/11792 to be very helpful to me how to query nested arrays. What I want now is to be able to update (push or replace) a value in the nested array. For example I want to replace all the "apple" values with "peach".
db.multiArr.insert({"ID" : "fruit1","Keys" : [["apple", "carrot", "banana"]]})
db.multiArr.insert({"ID" : "fruit2","Keys" : [["apple", "orange", "banana"]]})
I found 3 more questions about updating nested arrays but their answers do not seem to be helpful in this case. So how do we modify the values in the inner array?
I think what you're looking for is findAndyModify. See the documentation here.
Basically, you can include a query, remove an item, and update the document in one go. For example, if you want to:
Find all documents with 'apple' in the Keys subdocument
Remove all instances of 'apple'
Add 'peach' at the end of the array
It might look something like this:
db.multiArr.findAndModify({
query: { Keys : 'apple' },
update: { $pull : { Keys : 'apple' }}, { $push : { Keys : 'peach' }},
new: true
});
EDIT:
The above looks like it should work, but you can't use $push and $pull together in one update. It produces this error message:
findAndModifyFailed failed: {
"errmsg" : "exception: Field name duplication not allowed with modifiers",
"code" : 10150,
"ok" : 0
} at src/mongo/shell/collection.js:399
You're just going to have to do it in two updates:
// $push first or you won't be able to find the documents
db.multiArr.update({ Keys : 'apple' }, { $push : { Keys : 'peaches' }}, { multi : true });
db.multiArr.update({ Keys : 'apple' }, { $pull : { Keys : 'apple' }}, { multi : true });
To add to the previous answer, if you know the index of 'apple', you may hard code as below:
db.multiArr.update({Keys:"apple"}, {$set: {"Keys.0":"peaches"}}, {multi:true})

Resources