Updating embedded document property in Mongodb - mongodb

I have a document that looks like this:
{
"_id": 3,
"Slug": "slug",
"Title": "title",
"Authors": [
{
"Slug": "slug",
"Name": "name"
}
]
}
I want to update all Authors.Name based on Authors.Slug.
I tried this but it didn't work:
.update({"Authors.Slug":"slug"}, {$set: {"Authors.Name":"zzz"}});
What am I doing wrong here?

.update(Authors:{$elemMatch:{Slug:"slug"}}, {$set: {'Authors.$.Name':"zzz"}});

You can use update with array filters:
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#positional-update-arrayfilters
Probably something like this:
yourcollection.update(
{},
{
"$set": {
"Authors.$[element].Name": "zzz"
}
},
{
"multi": true,
"arrayFilters": [
{ "element.Slug": "slug" }
]
}
)
Ps.: it will not work in Robo3T as explained here: Mongodb 3.6.0-rc3 array filters not working?
However, you can try on a mongo shell with version >= 3.6.

yes, Rock's solution is working, P.S Notes is really helpful when trying Robo31..
If we want to update all
db.collection_name.update({}, {$set: {"Authors.$[].Name": "zzz"}})
If we want to update with matching object in an array
db.collection_name.update({}, {$set: {"Authors.$[i].Name": "zzz"}}, {arrayFilters: [{"i.Slug": "slug"}]})
Ref: https://jira.mongodb.org/browse/SERVER-1243

Related

Mongo pull multiple elements inside an array of object

I'm trying to pull one or multiple objects from an array and I noticed something odd.
Let's take the following document.
{
"_id" : UUID("f7e80c8e-6b4a-4741-95a3-2567cccf9e5f"),
"createdAt" : ISODate("2021-07-19T17:07:28.499Z"),
"description" : null,
"externalLinks" : [
{
"id" : "ZV8xMjM0NQ==",
"type" : "event"
},
{
"id" : "cF8xMjM0NQ==",
"type" : "planning"
}
],
"updatedAt" : ISODate("2021-07-19T17:07:28.499Z")
}
I wrote a basic query to pull one element of externalLinks which looks like
db.getCollection('Collection').update(
{
_id: {
$in: [UUID("f7e80c8e-6b4a-4741-95a3-2567cccf9e5f")]
}
}, {
$pull: {
externalLinks: {
"type": "planning",
"id": "cF8xMjM0NQ=="
}
}
})
And it's working fine. But it's getting trickier when I want to pull multiple element from the externalLinks. And I'm using the operator $in for that.
And the strange behaviour is here :
db.getCollection('Collection').update(
{
_id: {
$in: [UUID("f7e80c8e-6b4a-4741-95a3-2567cccf9e5f")]
}
}, {
$pull: {
externalLinks: {
$in: [{
"type": "planning",
"id": "cF8xMjM0NQ=="
}]
}
}
})
And this query doesn't work. The solution is to switch both field from externalLinks
and do something like :
$in: [{
"id": "cF8xMjM0NQ==",
"type": "planning"
}]
I tried multiple things like : $elemMatch, $positioning but it should be possible to pull multiple externalLinks.
I also tried the $and operator without success.
I could easily iterate over the externalLinks to update but it'd be too easy.
And it's tickling my brain to choose that solution.
Any help would be appreciate, thank you !
Document fields have order, and MongoDB compares documents based on the order of the fields see here, so what field you put first matters.
After MongoDB 4.2 we can also do pipeline updates, that can be sometimes bigger, but they are much more powerful, and feels more like programming.
(less declarative and pattern matching)
This doesn't mean that you need pipeline update in your case but check this way also.
Query
pipeline update
filter and keep members that the condition doesn't exist
Test code here
db.collection.update(
{_id: {$in: ["f7e80c8e-6b4a-4741-95a3-2567cccf9e5f"]}},
[{"$set":
{"externalLinks":
{"$filter":
{"input": "$externalLinks",
"cond":
{"$not":
[{"$and":
[{"$eq": ["$$this.id", "ZV8xMjM0NQ=="]},
{"$eq": ["$$this.type", "event"]}]}]}}}}}])

Mongodb Liqbase script findOneAndUpdate for json type values

I have code that uses existing collection that I want to update name field value which is present in taskMap key how i run with run liqubase changeset for that .
sample code :
"changes": [
{
"collectionName": "bulk_import_job_spec"
},
{
"findOneAndUpdate": {
{"_id": 101},
[{"$set": {"task_map": {"import": {"_id": 1, "name": "Category Association"}}}}]
},
{
"returnNewDocument": true
}
]
your questions is quite vague. Please provide some more details so that we can understand your issue.

mongodb $ causing error The positional operator did not find the match needed from the query

I’ve been trying to update the data in my mongoDB.
I want to update all products with a new productName field.
my data looks something like:
{
"id": "12345",
"products": [{
"id": 0
"productCode": "test",
"status": "PENDING",
},
{
"id": 1
"productCode": "test",
"status": "COMPLETE",
}],
}
When I try the following. I get this error The positional operator did not find the match needed from the query.
db.customers.updateMany(
{ id: "12345" },
{ $set: {
"products.$.productName": "Name here" }
}
)
If I do account.0.productName then it’s fine and updates. I’m not sure why $ is not working for me
db.customers.updateMany(
{ id: "12345" },
{ $set: {
"products.0.productName": "Name here" }
}
)
Positional operator is not working because you are not using the array into the find (first object)
If you try this query it will work as expected because you have the position finding by products.id.
Otherwise, if you don't have the position into array where update, yo can't use $ operator in this way. You need this query:
db.collection.update({
"id": "12345",
},
{
"$set": {
"products.$[].newField": "test2"
}
},
{
"multi": true
})
Mongo playground example here
Using $[] you can reference the array and add the value into each object.
$[] docs here
It says:
The all positional operator $[] indicates that the update operator should modify all elements in the specified array field.
That's exactly we want :)

Cannot add _id field to mongo subdocument in Mlab

In my Mlab mongo 3.2 database I have a collection that looks like this:
{
"_id": {
"$oid": "5752d....87985"
},
"name": "...etation",
"description": null,
"user_id": ".....",
"questions": [
{
"prompt": "The conclusions drawn seemed clear to most researchers, however, others were unconvinced, arguing that everything is open to ____________.",
"answer": "interpretation",
"created_at": "2014-11-09T14:59:38.154",
"updated_at": "2014-11-09T14:59:38.154",
"filled_answer": null
},
{
"id": 922,
"prompt": "His existential quest for Truth is in fact the key to his understanding and ____________ of the Bhagavad-Gītā.",
"answer": "interpretation",
"created_at": "2014-10-03T08:07:40.295",
"updated_at": "2014-10-03T08:07:40.295",
"filled_answer": null
},
}
There are two problems with the questions subdocument that I am struggling with:
Sometimes but not always there is a legacy "id" field that I want to $unset but my query is not working.
I want to add an _id ObjectID field where they do not already exist. Currently some have them and some don't.
I have tried a number of queries but none seem to work. For example:
db.droplets.updateMany({"questions.$._id": { $exists: false }},{ $set: {"questions.$._id": new ObjectId()}},{"multi": true, "upsert": true})
Mongo tells me "The positional operator did not find the match needed from the query"
Update
I have successfully found a way to delete all the questions using the following script:
db.droplets4.find().forEach(function (doc) {
doc.questions.forEach(function (question) {
if (question.id) {
delete question.id
}
});
db.droplets.save(doc);
});
But the same strategy is not working for adding Object IDs. This code does not work:
db.droplets4.find().forEach(function (doc) {
doc.questions.forEach(function (question) {
if (!question._id) { question._id = new ObjectId() }
});
db.droplets.save(doc);
});
This should work fine for you
db.droplets4.updateMany( {
"questions._id" : null
},{ $set: {"questions.$._id": new ObjectId()}},{"multi": true, "upsert": true})

How to update names field nested in an array in mongodb

I have this object and I'd like to update the name field "field" of all the document in the collections. I read the mongodb documentation and it says $rename doesn't work in this case. I should execute a forEach but I don't know how which command use
{
"name": "foo"
"array": [
"object": {
"field": "name"
}
]
}
Do it manually:
db.collection.find().forEach(function(doc) {
if (doc.array) {
doc.array.forEach(function(edoc) {
if (edoc.object) {
doc.object.new_field = edoc.object.field
delete edoc.object.field
}
})
db.test.update({ "_id" : doc._id }, doc)
}
})
This should get you started. It handles missing or empty array arrays, but not an array value of the wrong type, or an object value of the wrong type.
$rename modifier for update Ops should work (http://docs.mongodb.org/manual/reference/operator/update/rename/)
Imagine a collection like yours:
{
"name": "foo",
"array":[
{"field": "name" }
]
}
You will be able to do something like this:
db.rename.update({},{$rename:{"name":"newName"}});
And the document will be as follows:
{
"newName": "foo",
"array":[
{"field": "name" }
]
}
In order to update all the collection you should use the multi option as follows:
db.rename.update({},{$rename:{"name":"newName"}}, {multi:true})
Regards