Search and Push Array to Nested Object Array in MongoDB [duplicate] - node.js

This question already has answers here:
Mongodb $push in nested array
(4 answers)
Closed 4 years ago.
"date_added": {
"$date": "2018-02-27T21:34:31.144Z"
},
"malls": [
{
"name": "DFM",
"geocoordinates": "-6.7726935,39.2196418",
"region": "Kentucky",
"show_times": [],
"_id": {
"$oid": "5a95d3ed053cc1444eadaeae"
}
},
{
"name": "MkHouse",
"geocoordinates": "-6.8295944,39.2738459",
"region": "Kenon",
"show_times": [],
"_id": {
"$oid": "5a95d429053cc1444eadaeaf"
}
}
],
"title": "Black Panther",
I need to find/query malls with name == "DFM" and push data to show_times array, can anybody help! Which is the best way to handle this. I already query using _id and it worked and have this document. Now how can i push show_times? I'm using mongoose v5.5.1

Try this, It basically inserts the showtime where it found name field in malls array equal to DFM, $ operator is used for this
model.update(
{ _id: "givenObjectId",
"malls.name" : "DFM"
},
{
$push : {"malls.$.show_times" : data }
}
)
More details on the $ operator

Related

how can i sort data with a array element in mongodb without using unwind

this is my sample data in this I have a userId and a array "watchHistory", "watchHistory" array contains the list of videos that is watched by the user :
{
"_id": "62821344445c30b35b441f11",
"userId": 579,
"__v": 0,
"watchHistory": [
{
"seenTime": "2022-05-23T08:29:19.781Z",
"videoId": 789456,
"uploadTime": "2022-03-29T12:33:35.312Z",
"description": "Biography of Indira Gandhi",
"speaker": "andrews",
"title": "Indira Gandhi",
"_id": "628b45df775e3973f3a670ec"
},
{
"seenTime": "2022-05-23T08:29:39.867Z",
"videoId": 789455,
"uploadTime": "2022-03-31T07:37:39.712Z",
"description": "What are some healthy food habits to stay healthy",
"speaker": "morris",
"title": "Healthy Food Habits",
"_id": "628b45f3775e3973f3a670"
},
]
}
I need to match the userId and after that i need to sort it with "watchHistory.seenTime", seenTime field indicates when the user saw the video. so i need to sort like the last watched video should come first in the list.
I don't have permission to use unwind so can any one help me from this. Thank you.
If you are using MongoDB version 5.2 and above, you can use $sortArray operator in an aggregation pipeline. Your pipeline should look something like this:
db.collection.aggregate(
[
{"$match":
{ _id: '62821344445c30b35b441f11' }
},
{
"$project": {
_id: 1,
"userId": 1,
"__v": 1,
"watchHistory": {
"$sortArray": { input: "$watchHistory", sortBy: { seenTime: -1 }}
}
}
}
]
);
Please modify the filter for "$match" stage, according to the key and value you need to filter on. Here's the link to the documentation.
Without using unwind, it's not possible to do it via an aggregation pipeline, but you can use update method and $push operator, as a workaround like this:
db.collection.update({
_id: "62821344445c30b35b441f11"
},
{
$push: {
watchHistory: {
"$each": [],
"$sort": {
seenTime: -1
},
}
}
})
Please see the working example here

MongoDB is returning all Results in the find function [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.
I'm trying to perform a simple find using MongoDB, I'm new on it, so I don't know what is wrong, but it seems that it's always bringing all the results without filtering it.
You can run the code here and see what is happening:
https://mongoplayground.net/
Collection - Paste it here https://mongoplayground.net/ - FIRST Text Area
[
{
"collection": "collection",
"count": 10,
"content": [
{
"_id": "apples",
"qty": 5
},
{
"_id": "bananas",
"qty": 7
},
{
"_id": "oranges",
"qty": {
"in stock": 8,
"ordered": 12
}
},
{
"_id": "avocados",
"qty": "fourteen"
}
]
}
]
Find - Paste it here https://mongoplayground.net/ - SECOND Text Area
db.collection.find({
"content.qty": 5
})
Check the results and you will see the entire JSON as a result.
What Am I doing wrong? Thanks!
You can use $filter with $project after your $match in order to get just one item from the array:
db.collection.aggregate([
{ $match: { "content.qty": 5 }},
{
$project: {
collection: 1,
count: 1,
content: {
$filter: {
input: "$content",
as: "item",
cond: { $eq: [ "$$item.qty", 5 ]
}
}
}
}
}
])
Without having to unwind etc. You are getting all since $find returns the first document which matches and in your case that is the main doc.
See it working here
First, the query is bringing back what it should do. it bring you the document that satisfy your query, try to add element or more in the array you search in to see the difference.
Secondly, what you want to reach - to get only the specific elements in the nested array - can be done by aggregation you can read in it more here:
https://docs.mongodb.com/manual/aggregation/

MongoDb nested object selection [duplicate]

This question already has answers here:
Return only matched sub-document elements within a nested array
(3 answers)
Closed 5 years ago.
I have the multiple nested objects and lists, like below
{
"_id": "5a76be26ca96e22f08af2a19",
"testId": "123",
"testName": "summerTest",
"subjects": [
{
"subjectName": "Maths",
"testDetails": [
{
"testNumber": "0001",
"startTime": "2/18/18 13:30",
"endTime": "2/18/18 13:30",
"testDuriation": "01:00:00",
"questions": [
{...}
]
},
{
"testNumber": "0002",
"startTime": "2/18/18 13:30",
"endTime": "2/18/18 13:30",
"testDuriation": "01:00:00",
"questions": [
{...}
]
}
]
}
i want to select testNumber 0002 only. using mongoclient in my express js.
collection.find({ "testId": "123", "subjects.subjectName": "Maths", "subjects.testDetails.testNumber": "0002" }).toArray(function (err, data) {}..
But it will return entire TestId 123 document anyone help me. Thanks
Will be available
db.collection.aggregate([
{$unwind : '$subjects'},
{$project : {'_id': 0 , 'array' : '$subjects.testDetails'}},
{$unwind : '$array'},
{$match: {'array.testNumber' : '0002' }}
])
With a find you always return a whole document, so you need to add a projection to only show what you need.
By the way in your find filter there is an error, because if you want to filter only collections with a particular subjects.subjectName and subjects.testDetails.testNumber you need to use $elemMatch (https://docs.mongodb.com/manual/reference/operator/query/elemMatch/). If you don't do this it will return all document where in the subjects array there is one element with the first property and another one with the second property.

mongodb won't take $ as index in update query

I udpated my mongo instance from version 2.4 to 3.4 and all of my update queries stopped working where I was passing $ as index.
If I pass static 0 or 1 in the query it works fine, but earlier syntax of $ won't work at all.
Below is my query :
db.collection('users').update({"email": "u1#u1.com","companies":{"$elemMatch":{"id":"1487006991927"}}},
{
$set: {
"companies.$.details" : {"company_name":"hey updated"}
}
});
Response that I get :
{ result: { _t: 'UpdateResponse', ok: 1, n: 1, nModified: 1 },
This worked perfectly while I was on mongo vesrion 2.4 but not anymore. I can't always pass static 0 / 1 or index, what is the right way to do it ?
Also to note : Response says that 1 record was modified, but nothing was modified actually.
{
"_id": "589aa3509a248a3d7a01b784",
"businessAndPersonal": "true",
"companies": [
{
"details": {
"company_name": "afsfhey updated"
},
"locations": [],
"websites": [],
"id": "1487006991927"
},
{
"details": {
"company_name": "hey updated"
},
"locations": [],
"websites": [],
"id": "1487007435955"
}
]
}
Thanks in advance
Answer for my own question
I am using CosmosDB mongodb service as far they doesn't support positional operator of mongodb
Here is link that has discussion on positional array update via '$' query support

Mongoose : how to set a field of a model with result from an agregation

Here is my sample :
Two simple Mongoose models:
a Note model, with among other fields an id field that is a ref for the Notebook model.
a Notebook model, with the id I mentioned above.
My goal is to output something like that:
[
{
"notes_count": 7,
"title": "first notebook",
"id": "5585a9ffc9506e64192858c1"
},
{
"notes_count": 3,
"title": "second notebook",
"id": "558ab637cab9a2b01dae9a97"
}
]
Using aggregation and population on the Note model like this :
Note.aggregate(
[{
"$group": {
"_id": "$notebook",
"notes_count": {
"$sum": 1
}
}
}, {
"$project": {
"notebook": "$_id",
"notes_count": "$notes_count",
}
}]
gives me this kind of result :
{
"_id": "5585a9ffc9506e64192858c1",
"notes_count": 7,
"notebook": {
"_id": "5585a9ffc9506e64192858c1",
"title": "un carnet court",
"__v": 0
}
}
Forget about __v and _id fields, would be easy to handle with a modified toJSON function.
But in this function neither doc nor ret params gives me access to the computed notes_count value.
Obviously, I could manage this in the route handler (parse result and recreate the datas that will be returned) but, is there a proper way to do that with mongoose ?
You can't use the aggregate method to update. As you have noted, you'll need to use output from the aggregate constructor to update the relevant documents.
As the Mongoose aggregate method will return a collection of plain objects, you can iterate through this and utilise the _id field (or similar) to update the documents.

Resources