Nested query update in a loop in mongodb - mongodb

I have collection the structure of which is :-
Subscribed.insert({
"name": "Manager1",
"emailId": "arora.priya4172#gmail.com",
"category": "Finance",
"designation": 'Head',
"done": false,
"categorySubscribedUsers": [
{
"_id": "u4._id",
"username": "u4.profile.name",
"issuesNotToDisplay": []
},
{
"_id": "u4._id",
"username": "u4.profile.name",
"issuesNotToDisplay": []
},
{
"_id": "u4._id",
"username": "u4.profile.name",
"issuesNotToDisplay": []
}
]
});
I want to add the value in issuesNotToDisplay field. The query which I am using to update the issuesNotToDisplay field is as follows:-
Subscribed.update(
{
"_id":Subscribed.findOne({
"category": "Finance",
"categorySubscribedUsers.username" :"abhi"
})._id
},
{ "$addToSet": {
"categorySubscribedUsers.0.issueNotToDisplay": "25PEgZoMamLSTDdw7"
}}
)
This one I used in the console (browser and mongo) and it is working fine but when I replace the numerical value with the loop index (j here). It is not working why so? and what should be done to make it work.
The query with j index is as follows:-
Subscribed.update(
{
"_id":Subscribed.findOne({
"category": "Finance",
"categorySubscribedUsers.username" :"abhi"
})._id
},{
"$addToSet": {
"categorySubscribedUsers.j.issueNotToDisplay": "25PEgZoMamLSTDdw7"
}
}
)
Please anyone let me know how we can update the collection field inside a loop in mongodb.

Subscribed.update({
"category": "Finance",
"categorySubscribedUsers.username" : "u4.profile.name"
},
{
"$set":{
"categorySubscribedUsers.$.issueNotToDisplay": "25PEgZoMamLSTDdw7"
}
});

Related

MongoDB - How to get an exact query data using $all

I try to query data from MongoDB using this line of code:
forms = await AllForm.find({
answers: {
$all: [{ $elemMatch: { dateCreate: "2022-10-25" } }],
},
It was supposed to return dates that are only "2022-10-25", but it turns out that it selected all the dates with the result below:
"status": true,
"message": "LIST_FORM",
"forms": [
{
"_id": "635711356b220b918529c29a",
"formId": "635711356b220b918529c298",
"title": "Quality",
"department": "Quality",
"answers": [
{
"username": "jansenstan24sdasa#gmail.com",
"dateCreate": "2022-10-25",
"Keterangan": "john#nabas.com",
"Jam_Kerja": "14:09"
},
{
"username": "jansenstan2410#gmail.com",
"dateCreate": "2022-10-24",
"Keterangan": "john#dose.com",
"Jam_Kerja": "10:50"
}
],
"createdAt": "2022-10-24T22:27:01.673Z",
"updatedAt": "2022-10-24T22:32:27.683Z",
"__v": 0
},
{
"_id": "63571d2285d6fb180cfa9f84",
"formId": "63571d2285d6fb180cfa9f82",
"title": "Quality_2",
"department": null,
"answers": [
{
"username": "jansenstan24#gmail.com",
"dateCreate": "2022-10-25",
"Test": "john#nabatisnack.com",
"Date": "2022-10-12T00:00:00.000Z"
},
{
"username": "jansenstan24#gmail.com",
"dateCreate": "2022-10-25",
"Test": "john#nabatisnack.com",
"Date": "2022-10-12T00:00:00.000Z"
}
],
"createdAt": "2022-10-24T23:17:54.995Z",
"updatedAt": "2022-10-24T23:19:29.981Z",
"__v": 0
}
]
Can someone please tell me where did I do wrong with the query?
Think that the .find() query unable to complete such a complex projection.
You may look for aggregation query.
$match - With dot notation, find the document(s with forms array contain the document with dateCreate is "2022-10-25" in nested answers array.
$set - Set the answers array.
2.1. $filter - Filter the matched document in the answers array.
forms = await AllForm.aggregate([
{
$match: {
"answers.dateCreate": "2022-10-25"
}
},
{
$set: {
answers: {
$filter: {
input: "$answers",
cond: {
$eq: [
"$$this.dateCreate",
"2022-10-25"
]
}
}
}
}
}
])
Demo # Mongo Playground

Delete objects that met a condition inside an array in mongodb

My collection has array "name" with objects inside. I need to remove only those objects inside array where "name.x" is blank.
"name": [
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b57b",
"name": "abc",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e6"
},
"qty": "1.0",
"Unit": "pound,lbs"
},
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b430",
"name": "xyz",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
},{
"name.x": []
,
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
}
I tried to get all the ids where name.x is blank using python and used $pull to remove objects base on those ids.But the complete array got deleted.How can I remove the objects that meet the condition.
Think MongoDB update with aggregation pipeline meets your requirement especially to deal with the field name with ..
$set - Update the name array field by $filter name.x field is not an empty array.
db.collection.update({},
[
{
$set: {
name: {
$filter: {
input: "$name",
cond: {
$ne: [
{
$getField: {
field: "name.x",
input: "$$this"
}
},
[]
]
}
}
}
}
}
],
{
multi: true
})
Sample Mongo Playground

Mongoose find query on nested objects returns empty array

With Mongoose, I would like to be able to get a list of trainings by exercise _id parameter.
My training collection looks like this :
[
{
"_id": "617420adb9a7d7e02d591416",
"workout": {
"exercises": [
{
"_id": "61742066b9a7d7e02d5913ea",
"name": "Exercise 1"
}
],
"name": "Workout 1",
"_id": "617420a1b9a7d7e02d591401"
},
},
{
"_id": "617420b5b9a7d7e02d59141f",
"workout": {
"exercises": [
{
"_id": "61742066b9a7d7e02d5913ea",
"name": "Exercise 2"
}
],
"name": "Workout 2",
"_id": "617420a1b9a7d7e02d591401"
},
},
{
"_id": "6174226830610e43b0f6a283",
"workout": {
"exercises": [
{
"_id": "6174225630610e43b0f6a267",
"name": "Exercise 2"
}
],
"name": "Workout 3",
"_id": "6174226030610e43b0f6a275"
},
}
]
Based on MongoDB documentation I tried something like this :
this.trainingModel.find({
'workout.exercises._id': '61742066b9a7d7e02d5913ea',
});
This code returns an empty array. I was expecting to have two trainings (the two first of collection).
I also did this :
this.trainingModel.find({
'workout.exercises': { _id: '61742066b9a7d7e02d5913ea' },
});
But I also get an empty array as response.
I have just found the solution. As #turivishal said I had first to convert the string id to ObjectId. But then I also had to change the query like this :
this.trainingModel.find({
'workout.exercises._id': new Types.ObjectId('my_string_id'),
});

mongodb query update select nested fields

this is my document in mongo:
"calendar": {
"_id": "5cd26a886458720f7a66a3b8",
"hotel": "5cd02fe495be1a4f48150447",
"calendar": [
{
"_id": "5cd26a886458720f7a66a413",
"date": "1970-01-01T00:00:00.001Z",
"rooms": [
{
"_id": "5cd26a886458720f7a66a415",
"room": "5cd17d82ca56fe43e24ae5d3",
"price": "",
"remaining": 0,
"reserved": 0
},
{
"_id": "5cd26a886458720f7a66a414",
"room": "5cd17db6ca56fe43e24ae5d4",
"price": "",
"remaining": 0,
"reserved": 0
}
]
},
}
I need to update the objects in the inner rooms array . I tried a query that selects a matching element no syntax error but an error comes in:
"errmsg" : "The field 'calendar.0.rooms.0.price' must be an array but
is of type string in document {_id:
ObjectId('5cd26a886458720f7a66a3b8')}",
and this my query:
db.calendars.updateOne({_id:ObjectId("5cd26a886458720f7a66a3b8"),
"calendar":{"$elemMatch":{"_id":ObjectId("5cd26a886458720f7a66a413"),"rooms._id":
ObjectId("5cd26a886458720f7a66a415")}}},
{"$push":{"calendar.$[outer].rooms.$[inner].price":"100000"}}, {"arrayFilters":[{"outer._id":ObjectId("5cd26a886458720f7a66a413")},{"inner._id":ObjectId("5cd26a886458720f7a66a415")}]})
this is some reference I found in StackOverflow but not helped:
Updating a Nested Array with MongoDB
You can use below query
db.getCollection("test").updateOne(
{
"_id": ObjectId("5cd26a886458720f7a66a3b8"),
"calendar.calendar": {
"$elemMatch": {
"_id": ObjectId("5cd26a886458720f7a66a413"),
"rooms._id": ObjectId("5cd26a886458720f7a66a415")
}
}
},
{ "$set": { "calendar.calendar.$[outer].rooms.$[inner].price": "100000" } },
{
"arrayFilters": [
{ "outer._id": ObjectId("5cd26a886458720f7a66a413") },
{ "inner._id": ObjectId("5cd26a886458720f7a66a415") }
]
}
)
I will update my answer with some explanation afterward

How to get sum of child entries for hierarchical documents?

I have a document of the following form:
{
"name": "root1",
"children": [{
"name": "A",
"children": [{
"name": "A1",
"items": 20
}, {
"name": "A2",
"items": 19
}],
"items": 8
}, {
"name": "B",
"items": 12
}],
"items": 1
}
That is, each level has a "name" field, an "items" field, and optionally a children field. I would like to run a query which returns the total number of items for each root. In this example, it should return (since 20+19+8+12+1=60)
{ "_id" : "root1", "items" : 60 }
However, each document can have arbitrarily many levels. That is, this example has two to three children below the root, but other documents may have more. That is, I cannot do something like
db.myCollection.aggregate( { $unwind : "$children" },
{ $group : { _id : "$name", items: { $sum : "$items" } } } )
What sort of query will work?
There really is no way to descend arrays to arbitrary depths using the aggregation framework. For this sort of structure you need to use mapReduce where you can programatically do this:
db.collection.mapReduce(
function () {
var items = 0;
var action = function(current) {
items += current.items;
if ( current.hasOwnProperty("children") ) {
current.children.forEach(function(child) {
action( child );
});
}
};
action( this );
emit( this.name, items );
},
function(){},
{ "out": { "inline": 1 } }
)
If you do not want mapReduce then consider another structure for your data and do things differently:
{ "name": "root1", "items": 1, "path": [], "root": null },
{ "name": "A", "items": 8, "path": ["root1"], "root": "root1" },
{ "name": "A1", "items": 20, "path": ["root1", "A"], "root": "root1" },
{ "name": "A2", "items": 19, "path": ["root1", "A"], "root": "root1" },
{ "name": "B", "items": 12, "path": ["root1"], "root": "root1" }
Then you just have a simple aggregate:
db.collection.aggregate([
{ "$group": {
"_id": {
"$cond": [
"$root",
"$root",
"$name"
]
},
"items": { "$sum": "$items" }
}}
])
So if you take a different approach to mapping a hierarchy then doing things such as aggregating totals for paths is much easier without the recursive inspection that would otherwise be required.
The approach that you need depends on your actual usage requirements.