Query to update showing 0 records updated mongo - mongodb

Am using below query in db.getcolletion
db.getCollection('publickdata').find({"mediatorProf" : "ctvdl Without audieo",
"ProfileName":"p2_max_dls",ProfileDetails:
{ $elemMatch: { Name: "psMaxdetail", Value: "Mozilla 13" } }})
I need to update Value: Mozilla 13 to Value: Mozilla 12
Am using below query:
db.collection.update( // or updateMany directly, removing the flag for 'multi'
{"elemMatch.Value":"Mozilla 13"},
{$set:{"elemMatch.$[].Value":"Mozilla 12"}}, // notice the empty brackets after '$' opearor
false,
true
)
output showing: Updated 0 records provide suggestions.
document is:
/* 1 */
{
"_id" : ObjectId("5e31a24faa0f99e"),
"lastUpdateDate" : ISODate("2020-02-29T16:18:39.664Z"),
"mediatorProf" : "ctvdl Without audieo",
"ProfileName" : "p2_max_dls",
"ProfileDetails" : [
{
"Name" : "psMaxdetail",
"Value" : "Mozilla 13"
},
{
"Name" : "iptvSupported",
"Value" : "N"
}
]
}

Use $[identifier] along with arrayFilters.
db.publickdata.updateMany(
{
"mediatorProf": "ctvdl Without audieo",
"ProfileName": "p2_max_dls"
},
{
$set:{
"ProfileDetails.$[elem].Value": "Mozilla 12"
},
$unset:{
"ProfileDetails.$[elem].AttributeValue": 1
}
},
{
multi: true,
arrayFilters: [{"elem.Name": "psMaxdetail", "elem.Value": "Mozilla 13"}]
}
);

Related

MongoDB - Update an Key

I have been trying to update an Object for this collection. Below is the collection. Looking for Server 3.6 version.
Here The ask is Need to update the class name from "HISTORY" to " HISTORY_NEW". Need to do, for some students in the class. Need a query that will select all student records in student collection with "HISTORY" class in it and update them to "HISTORY_NEW ". I have around 30,000 records and not getting a bulk update method.
{
"_id" : ObjectId("611f90aa43f77a728879c395"),
"studentId" : "stu1",
"classes" : {
"History" : {
"TeacherName" : "T1",
"Marks" : [
{
"Internal": 15
}
]
},
"Geography" : {
"TeacherName" : "T2",
"Marks" : [
{
"Internal" : 20
}
]
}
},
"updateDate" : ISODate("2021-10-12T11:40:47.156Z")
}
This is the result I am expecting
{
"_id" : ObjectId("611f90aa43f77a728879c395"),
"studentId" : "stu1",
"classes" : {
"HISTORY_NEW" : {
"TeacherName" : "T1",
"Marks" : [
{
"Internal": 15
}
]
},
"Geography" : {
"TeacherName" : "T2",
"Marks" : [
{
"Internal" : 20
}
]
}
},
"updateDate" : ISODate("2021-10-12T11:40:47.156Z")
}
.Or is that even possible with the kind of collection above or going via code route?
So far this is what I have, without any success.
Get all students' Ids and then update the Class name. But that is also not working and don't think it is smart to update DB 30,000 times.
var studentIds =[];
db.studentSubject.find({"classes.History":{$exists:true}})
.forEach(function(u) { studentIds.push(u.studentId) })
studentIds.forEach(function(studentId) {
var result;
try {
result =db.studentSubject.updateOne(
{studentId:studentId},
{ $set : {"classes.History": "HISTORY_NEW",}},
{ upsert: false});
} catch (e) {
print(e);
}
});
From your scenario, you need $rename operator.
As discussed in the comment, you don't need to fetch each document to get studentId and then pass it to update each document. Just bulk update by checking the document has classes.History field.
db.collection.update({
"classes.History": {
$exists: true
}
},
{
$rename: {
"classes.History": "classes.HISTORY_NEW"
}
},
{
upsert: false,
multi: true
})
Sample Mongo Playground

mongo updateMany $set nested array when some docs do not contain the path

I have a seemingly straight forward query to update the names of like objects in a mongo doc. But it fails as not all docs have comment.. what should i be looking for in the docs get around this and update only the docs that have likes on comments?
return this.model.updateMany(
{
comments: {
$exists: true
}
},
{
$set: {
'comments.likes.$[like].actor.firstName': user.firstName,
'comments.likes.$[like].actor.lastName': user.lastName,
},
},
{
multi: true,
arrayFilters: [
{ 'like.actor.username': user.username },
],
},
);
The problem is that not all comments are liked.. so then the query complains:
WriteError: The path 'comments.likes' must exist in the document in order to apply array updates.
Full output:
WriteError: The path 'comments.likes' must exist in the document in order to apply array updates.
Details:
WriteError({
"index" : 0,
"code" : 2,
"errmsg" : "The path 'comments.likes' must exist in the document in order to apply array updates.",
"op" : {
"q" : {
"comments" : {
"$exists" : true
}
},
"u" : {
"$set" : {
"comments.likes.$[like].actor.firstName" : "GGGJOHN",
"comments.likes.$[like].actor.lastName" : "Carmichael"
}
},
"multi" : true,
"upsert" : false,
"arrayFilters" : [
{
"like.actor.username" : "john.carmichael"
}
]
}
})
WriteError#src/mongo/shell/bulk_api.js:461:48
Bulk/mergeBatchResults#src/mongo/shell/bulk_api.js:841:49
Bulk/executeBatch#src/mongo/shell/bulk_api.js:906:13
Bulk/this.execute#src/mongo/shell/bulk_api.js:1150:21
DBCollection.prototype.updateMany#src/mongo/shell/crud_api.js:655:17
#(shell):1:1
Here is an illustration of the doc in q, where comments is an array and the likes on a single comment is also an array:
what if you added
under match part of the update part query you are checking if likes attribute exists in the comments object
return this.model.updateMany(
{
"comments.likes": { // <---
$exists: true
}
},
{
$set: {
'comments.likes.$[like].actor.firstName': user.firstName,
'comments.likes.$[like].actor.lastName': user.lastName,
},
},
{
multi: true,
arrayFilters: [
{ 'like.actor.username': user.username },
],
},
);

How to update Meteor array element inside a document

I have a Meteor Mongo document as shown below
{
"_id" : "zFndWBZTvZPgSKXHP",
"activityId" : "aRDABihAYFoAW7jbC",
"activityTitle" : "Test Mongo Document",
"users" : [
{
"id" : "b1#gmail.com",
"type" : "free"
},
{
"id" : "JqKvymryNaCjjKrAR",
"type" : "free"
},
],
}
I want to update a specific array element's email with custom generated id using Meteor query something like the below.
for instance, I want to update the document
if 'users.id' == "b1#gmail.com" then update it to users.id = 'SomeIDXXX'
So updated document should looks like below.
{
"_id" : "zFndWBZTvZPgSKXHP",
"activityId" : "aRDABihAYFoAW7jbC",
"activityTitle" : "Test Mongo Document",
"users" : [
{
"id" : "SomeIDXXX",
"type" : "free"
},
{
"id" : "JqKvymryNaCjjKrAR",
"type" : "free"
},
],
}
I have tried the below but didnt work.
Divisions.update(
{ activityId: activityId, "users.id": emailId },
{ $set: { "users": { id: _id } } }
);
Can someone help me with the relevant Meteor query ? Thanks !
Your query is actually almost right except for a small part where we want to identify the element to be updated by its index.
Divisions.update({
"activityId": "aRDABihAYFoAW7jbC",
"users.id": "b1#gmail.com"
}, {
$set: {"users.$.id": "b2#gmail.com"}
})
You might need the arrayFilters option.
Divisions.update(
{ activityId: activityId },
{ $set: { "users.$[elem].id": "SomeIDXXX" } },
{ arrayFilters: [ { "elem.id": "b1#gmail.com" } ], multi: true }
);
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/
You need to use the $push operator instead of $set.
{ $push: { <field1>: <value1>, ... } }

How to write a query to get all documents where field doesn't matches

I am having some trouble writing a query where I want to get all documents where they don't have a single subdocument where its property IsCurrentRevision is true. In other words, only getting documents that don't have a single revision marked as current.
What I have so far is:
{StartTimeUtc: {$gte: new ISODate('12/14/2019')},
EndTimeUtc: {$lte: new ISODate('01/21/2020')},
IsDeleted: false, 'MyDocument.IsCurrentRevision': false,
"MyDocument.1.IsCurrentRevision" : {$exists: false}}
This gets me somewhere, but the issue is that I have to manually query the index. In this case, the above query returns all documents with only 1 revision (so only one element in the sub document array), that doesn't have its revision marked as current. Thus if I wanted to get documents that have 2 revisions, with the second one marked as false as well I would need to update the query to be:
{StartTimeUtc: {$gte: new ISODate('12/14/2019')},
EndTimeUtc: {$lte: new ISODate('01/21/2020')},
IsDeleted: false, 'MyDocument.1.IsCurrentRevision': false,
"MyDocument.2.IsCurrentRevision" : {$exists: false}}
This is obviously tedious, is there a better way? If it helps, I am using Mongo Compass
Edit:
Here is how my document looks like
{
_id: Guid,
TemplateId: guid,
StartTimeUtc: DateTime,
EndTimeUtc: DateTime
..
..
SoapNoteRevisions: Array {
_id: Guid,
IsCurrentRevision: boolean,
..
..
}
}
I got rid of the unneeded bits as the document itself has a fair bit of fields within the revision as well (another sub array)
If you need documents where MyDocument elements/objects doesn't have IsCurrentRevision : true, try below query :
db.collection.find({'MyDocument.IsCurrentRevision': {$ne : true}})
If using aggregation :
db.collection.aggregate([{$match : {'MyDocument.IsCurrentRevision': {$ne : true}}}])
Collection Data :
/* 1 */
{
"_id" : ObjectId("5e27282ad02e05b69498b814"),
"MyDocument" : [
{
"IsCurrentRevision" : false
},
{
"IsCurrentRevision" : false
},
{
"IsCurrentRevision" : false
}
]
}
/* 2 */
{
"_id" : ObjectId("5e272839d02e05b69498b947"),
"MyDocument" : [
{
"IsCurrentRevision" : true
},
{
"IsCurrentRevision" : true
},
{
"IsCurrentRevision" : true
}
]
}
/* 3 */
{
"_id" : ObjectId("5e272846d02e05b69498ba5c"),
"MyDocument" : [
{
"IsCurrentRevision" : false
},
{
"IsCurrentRevision" : true
},
{
"IsCurrentRevision" : false
}
]
}
Result :
/* 1 */
{
"_id" : ObjectId("5e27282ad02e05b69498b814"),
"MyDocument" : [
{
"IsCurrentRevision" : false
},
{
"IsCurrentRevision" : false
},
{
"IsCurrentRevision" : false
}
]
}

$inc vs. $setOnInsert in MongoCollection.findOneAndUpdate()

I'm trying to implement a 'server-side counter-versioned' item in mongodb and trying to do following /* using Java API */
Document dbDoc = dbCollection.findOneAndUpdate(
new Document("_id", "meta"),
new Document("$inc", new Document("version", 1))
.append("$setOnInsert", new Document("version", 0)),
new FindOneAndUpdateOptions().upsert(true)
.returnDocument(ReturnDocument.AFTER));
Assumed logic is simple: if there is no record in database - start counting from zero (and with a whole fresh new object), otherwise - increment counter.
Code sample fails with: 'Cannot update 'version' and 'version' at the same time'
My assumption is that in 'upsert' mode mongo should only use "$setOnInsert" when no matching item is found - but it works in some other way.
Is it possible to implement such operation in one atomic mongoDB call?
PS: MongoDB documentation regarding findOneAndUpdate() and upsert() is fuzzy - at least I cannot get why this error arizes from their description.
Also there is similar question here - findAndModify fails with error: "Cannot update 'field1' and 'field1' at the same time - accepted, but again with no clear reasoning.
You can just remove the update operator of $setOnInsert as this will be set to the value specified in the $inc operator if the document does not exist
https://docs.mongodb.com/v3.2/reference/operator/update/inc/#behavior
If the field does not exist, $inc creates the field and sets the field to the specified value.
Example from the mongo shell:
> db.dropDatabase()
{ "ok" : 1 }
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true})
{ "_id" : "meta", "version" : 1 }
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true})
{ "_id" : "meta", "version" : 2 }
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true})
{ "_id" : "meta", "version" : 3 }
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true})
{ "_id" : "meta", "version" : 4 }
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true})
{ "_id" : "meta", "version" : 5 }
If you need to set a given version on the first initial insert, then mongodb does not support any operators to support this atomically, however the follow would be safe and is a common workaround:
> db.dropDatabase()
{ "dropped" : "test", "ok" : 1 }
> function updateMeta(){
... function update(){
... return db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {returnNewDocument: true});
... }
...
... var result = update();
...
... if(result === null){
... db.test.insert({_id: "meta", version: -10});
... result = update();
... }
...
... return result;
... }
>
> updateMeta()
{ "_id" : "meta", "version" : -9 }
> updateMeta()
{ "_id" : "meta", "version" : -8 }
> updateMeta()
{ "_id" : "meta", "version" : -7 }
> updateMeta()
{ "_id" : "meta", "version" : -6 }
> updateMeta()
{ "_id" : "meta", "version" : -5 }
>