Update array of document embedded - mongodb

A question if I want to update all documents embedded in a document, how could I do? because when you run the following command
.update({'sites':{$elemMatch:{'status':true}}},{$set:{'sites.$.status': false}},{multi:true})
only the first found embedded document is updated
documents example:
{
'_id': 1,
sites: [
{'status':true,'url':'http://google.com'},
{'status':true,'url':'https://university.mongodb.com'},
{'status':true,'url':'https://docs.mongodb.org'}
]}

This isn't possible, the closes you can get is to update the entire element. e.g.:
db.test.update({
_id: 1
},
{
$set: {
sites: [
{'status':true,'url':'http://1.example.com'},
{'status':true,'url':'http://2.example.com'},
{'status':true,'url':'http://3.example.com'},
]
}
})

Related

MongoDB: Updating a document with existing fields using aggregation

I am new to mongodb, I am learning from some Udemy courses and I want to know how I can update a document existing field without overwriting it.
I have the following collection with these documents:
enter image description here
I want to add new warehouses in the "item":"drafts" within the stock field.
What I am trying is:
enter image description here
And giving the output it seems that is working, but when I do again db.matrices.find(), what I get is the exactly same output that in the first image.
How can I update it? I have tried also the update method, but does not do what I want to do.
Thanks!
PD: I am using linux mint, with mongo v5.0.3, and mongosh v1.1.1
You are using the aggregate pipeline, this does not update the document in the DB, it just retrieves the result. starting in Mongo version 4.2+ you can now use an aggregation pipeline ( with some limitations ) to update a document, like so:
db.collection.updateOne({
item: "drafts"
},
[
{
$set: {
stock: {
$concatArrays: [
"$stock",
[
{
"warehouse": "A",
qty: 20
}
]
]
}
}
}
])
Mongo Playground
I will just say that this specific update is very simple, there is no need to use an aggregation pipeline for it. a simple use of the $push operator in the update field will suffice in a "normal" update:
db.collection.updateOne({
item: "drafts"
},
{
$push: {
stock: {
"warehouse": "A",
qty: 20
}
}
})
Mongo Playground

Can't remove object in array using Mongoose

This has been extensively covered here, but none of the solutions seems to be working for me. I'm attempting to remove an object from an array using that object's id. Currently, my Schema is:
const scheduleSchema = new Schema({
//unrelated
_id: ObjectId
shifts: [
{
_id: Types.ObjectId,
name: String,
shift_start: Date,
shift_end: Date,
},
],
});
I've tried almost every variation of something like this:
.findOneAndUpdate(
{ _id: req.params.id },
{
$pull: {
shifts: { _id: new Types.ObjectId(req.params.id) },
},
}
);
Database:
Database Format
Within these variations, the usual response I've gotten has been either an empty array or null.
I was able slightly find a way around this and accomplish the deletion by utilizing the main _id of the Schema (instead of the nested one:
.findOneAndUpdate(
{ _id: <main _id> },
{ $pull: { shifts: { _id: new Types.ObjectId(<nested _id>) } } },
{ new: true }
);
But I was hoping to figure out a way to do this by just using the nested _id. Any suggestions?
The problem you are having currently is you are using the same _id.
Using mongo, update method allows three objects: query, update and options.
query object is the object into collection which will be updated.
update is the action to do into the object (add, change value...).
options different options to add.
Then, assuming you have this collection:
[
{
"_id": 1,
"shifts": [
{
"_id": 2
},
{
"_id": 3
}
]
}
]
If you try to look for a document which _id is 2, obviously response will be empty (example).
Then, if none document has been found, none document will be updated.
What happens if we look for a document using shifts._id:2?
This tells mongo "search a document where shifts field has an object with _id equals to 2". This query works ok (example) but be careful, this returns the WHOLE document, not only the array which match the _id.
This not return:
[
{
"_id": 1,
"shifts": [
{
"_id": 2
}
]
}
]
Using this query mongo returns the ENTIRE document where exists a field called shifts that contains an object with an _id with value 2. This also include the whole array.
So, with tat, you know why find object works. Now adding this to an update query you can create the query:
This one to remove all shifts._id which are equal to 2.
db.collection.update({
"shifts._id": 2
},
{
$pull: {
shifts: {
_id: 2
}
}
})
Example
Or this one to remove shifts._id if parent _id is equal to 1
db.collection.update({
"_id": 1
},
{
$pull: {
shifts: {
_id: 2
}
}
})
Example

MongoDB: Add field to all objects in array, based on other fields on same object?

I am fairly new to MongoDB and cant seem to find a solution to this problem.
I have a database of documents that has this structure:
{
id: 1
elements: [ {elementId: 1, nr1: 1, nr2: 3}, {elementId:2, nr1:5, nr2: 10} ]
}
I am looking for a query that can add a value nr3 which is for example nr2/nr1 to all the objects in the elements array, so that the resulting document would look like this:
{
id: 1
elements: [ {elementId: 1, nr1: 1, nr2: 3, nr3:3}, {elementId:2, nr1:5, nr2: 10, nr3: 2} ]
}
So I imagine a query along the lines of this:
db.collection.updateOne({id:1}, {$set:{"elements.$[].nr3": nr2/nr1}})
But I cant find how to get the value of nr2 and nr1 of the same object in the array.
I found some similar questions on stackoverflow stating this is not possible, but they were 5+ years old, so I thought maybe they have added support for something like this.
I realize I can achieve this with first querying the document and iterate over the elements-array doing updates along the way, but for the purpose of learning I would love to see if its possible to do this in one query.
You can use update with aggregation pipeline starting from MongoDB v4.2,
$map to iterate loop of elements
divide nr2 with nr1 using $divide
merge current object and new field nr3 using $mergeObjects
db.collection.updateOne(
{ id: 1 },
[{
$set: {
elements: {
$map: {
input: "$elements",
in: {
$mergeObjects: [
"$$this",
{ nr3: { $divide: ["$$this.nr2", "$$this.nr1"] } }
]
}
}
}
}
}]
)
Playground
db.collection.update(
{ id:1},
{ "$set": { "elements.$[elem].nr3":elements.$[elem].nr2/elements.$[elem].nr1} },
{ "multi": true }
);
I guess this should work

Pymongo - Query mongdb for first array elemnet by query of list of values

Given collection:
{
"_id" : "1.1000038",
"recomendation" : [
"1.6739718"
]
}
/* 2 */
{
"_id" : "1.1000069",
"recomendation" : [
"1.9185509",
"1.9051998",
"1.9034279",
"1.8288046",
"1.8152670",
"1.858775",
"1.6224229",
"1.4591674",
"1.3862464",
"1.3427739",
"1.3080062",
"1.3003608",
"1.1694619",
"1.1634683",
"1.1590664",
"1.1524146",
"1.754599",
"1.700837",
"1.763617"
]
}
I need to query the MongoDB for a list of values and get the first element of the list of values
here is the query by mongo syntax
db.getCollection('similar_articles').find({"_id":{$in:["1.1000069","1.1000038"]}})
I don't want to filter it on the python side because it's can be too big.
I didn't find any documentation on it
desire output:
Pandas DataFrame
_id recom
1.1000038 1.6739718
1.1000069 1.9185509
I don't know pymongo so well, but you need this query:
First $match by _ids into the arreay (this is like the find you have).
And later use $project to create the field recom (you can use "recomendation" to overwrite the existing field) and set the value as the first into the array.
db.collection.aggregate([
{
"$match": { "_id": { "$in": [ "1.1000069", "1.1000038" ] } }
},
{
"$project": { "recom": { "$arrayElemAt": [ "$recomendation", 0 ] } }
}
])
Example here
Looking the doumentation it seems you only need to copy and paste this query.

How to deselect one object in array MongoDB? [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 3 years ago.
In my situation I just need my result but without my objectID in my array.
This is my method :
return Room.findOne(
{
_id: idRoom,
participants: {$elemMatch: {$ne: this.currentUser.profile}},
},
{
'participants.$': 1,
}
)
With elementMatch, the problem is when you found the object, only the first object is returned.
This is my result :
"result": {
"_id": "5da5e77f51e08708b79565e8",
"participants": [
"5da4d5b40cc94f04a7aaad40"
],
And this is the real result I need
"result": {
"_id": "5da5e77f51e08708b79565e8",
"participants": [
"5da4d5b40cc94f04a7aaad40"
"fwnert9248yrhnqwid13982r" // I have another participants
],
And my model is just like this :
const RoomSchema = new Schema({
participants: [{type: Schema.Types.ObjectId,ref: 'Profile'}],
...
}, options)
For others reasons, I can't use aggregate, thank you if you have the solution
So I think you are trying to shape a resultset in mongo with the findOne() method, and any use of the aggregation pipeline framework is out of the question and unavailable for other reasons.
I am not sure this is possible. I believe you will need to perform multiple steps to achieve your desired results. If you can use aggregation pipeline framework here is a pipeline to suit the desired results (I believe)...
db.Room.aggregate(
[
{
"$match": { _id: ObjectId(idRoom)}
},
{
$project: {
"participants": {
$filter: {
input: "$participants",
as: "participant",
cond: {$ne: ["$$participant", this.currentUser.profile] }
}
}
}
}
]
)
...but if you cannot use aggregation pipeline then here is a mongoshell script that accomplishes the task in several steps. The strategy is to capture the whole document by _id then remove the data element from the array then echo the results...
var document = db.Room.findOne( { _id: ObjectId("5da64a62cd63abf99d11f210") } );
document.participants.splice(document.participants.indexOf("5da4d5b40cc94f04a7aaad40"), 1);
document;