MongoDB (Mongoose) database query question - mongodb

I'm trying to get all the documents from a collection that have a variable amount of failed exams.
My collection is the following:
I have to retrieve all student that have for example 3 scores lower than 10.
The query I am currently running is the following:
Student.aggregate([
{
$project: {
_id: 0,
name: 1,
students: {
count: {
$size: {
$filter: {
input: "$results",
as: "result",
cond: {$lt: ["$$result.score", 10]}
}
}
}
}
}
}
])
How would I check if the count is $gte then for example 3?
My current output:

You are almost 100% done already! Just add
{$match: {"students.count": {$gte: 3}}
as a stage in the pipeline after $project.

Related

Mongodb Aggregate - How can i filter an array by multilpe array indexes?

I have a huge array and I need to get only array indexes that are multiple by 12. I thought using $filter, but I'm struggling in the cond parameter.
I'm using aggregate because there is more stuff that i need to do, but I'm stuck in this filter part.
data : [3,4,5,6,...,etc, <more 5000 items> ]
query:
db.test.aggregate([{$project:{filtered_values: {$filter:{input: '$data', as:data ,cond: { ??? some witchcraft ???} }}}}])
Expected result:
[data[0],data[12],data[24],data[36],data[i%12 ===0]]
How can i reach this result with aggregate? Or if is $filter the best solution?
Try this:
db.collection.aggregate([
{
$set: {
data: {
$map: {
input: { $range: [0, { $size: "$data" }, 12] },
as: "i",
in: { $arrayElemAt: ["$data", "$$i"] }
}
}
}
}
])

MongoDB map filtered array inside another array with aggregate $project

I am using Azure Cosmos DB's API for MongoDB with Pymongo. My goal is to filter array inside array and return only filtered results. Aggregation query works for the first array, but returns full inside array after using map, filter operations. Please find Reproducible Example in Mongo Playground: https://mongoplayground.net/p/zS8A7zDMrmK
Current query use $project to filter and return result by selected Options but still returns every object in Discount_Price although query has additional filter to check if it has specific Sales_Week value.
Let me know in comments if my question is clear, many thanks for all possible help and suggestions.
It seemed you troubled in filtering nested array.
options:{
$filter: {
input: {
$map: {
input: "$Sales_Options",
as: 's',
in: {
City: "$$s.City",
Country: "$$s.Country",
Discount_Price: {
$filter: {
input: "$$s.Discount_Price",
as: "d",
cond: {
$in: ["$$d.Sales_Week", [2, 7]]
}
}
}
}
}
},
as: 'pair',
cond: {
$and: [{
$in: [
'$$pair.Country',
[
'UK'
]
]
},
{
$in: [
'$$pair.City',
[
'London'
]
]
}
]
}
}
}
Working Mongo plaground. If you need price1, you can use $project in next stage.
Note : If you follow the projection form upper stage use 1 or 0 which is good practice.
I'd steer you towards the $unwind operator and everything becomes a lot simpler:
db.collection.aggregate([
{$match: {"Store": "AB"}},
{$unwind: "$Sales_Options"},
{$unwind: "$Sales_Options.Discount_Price"},
{$match: {"Sales_Options.Country": {$in: [ "UK" ]},
"Sales_Options.City": {$in: [ "London" ]},
"Sales_Options.Discount_Price.Sales_Week": {$in: [ 2, 7 ]}
}
}
])
Now just $project the fields as appropriate for your output.

how to convert epoch time stored in nested field to date mongodb

I have a nested field msgs.crtDtTm inside a mongodb which has epoch date (1554120000)stored as string. I need to convert msgs.crtDtTm to Date format to apply $gte (which is not working in String format).
cond: { $gte: [ "$msg.crtDtTm", "1554120000" ] }
I tried this but greater than operation not performed. It is returning all the nested elements without filtering.
You can convert string to date by this command :
new Date("1554120000")
Like this :
db.YourCollection.find({"created_at" : { $gte : new Date("1554120000") }});
in your example :
cond: {$msg.crtDtTm : { $gte: new Date("1554120000") }}
Let me know the result please .
This link is also useful
Once your time april 1,2019 being converted into ms and then to type of string in your code, it would be easy that way(as converting one element vs n values in DB - altogether it might be easy for that format to be converted into ms in code), then use this query to retrieve elements that match your criteria :
db.yourCollection.aggregate([
{$match: {'msgs.crtDtTm': {$gt: '1554120000'}}},
{$addFields: {
msgs: {$filter: {
input: '$msgs',
as: 'msg',
cond: {$gt: ['$$msg.crtDtTm', '1554120000']}
}}
}}
])
You could achieve similar using $unwind on msgs & then $match finally $group or $match to start with, which ever is feasible you can go ahead. Something like this :
db.yourCollection.aggregate([{
$match: {
'msgs.crtDtTm': { $gt: '1554120000' }
}
},
{ $unwind: "$msgs" },
{
$match: {
'msgs.crtDtTm': { $gt: '1554120000' }
}
}, { $group: { _id: '$_id', msgs: { $push: '$msgs' }, docs: { $first: '$$ROOT' } } }, { $addFields: { 'docs.msgs': '$msgs' } }, { $replaceRoot: { newRoot: '$docs' } }])
Lastly, It would be a better idea if you can store the same format which will be used to query.

MongoDB mongoose $elemMatch for multiple results [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
I have a query that should return multiple subdocuments from an array in a document, based on a timestamp range criteria. I first choose the main documents by specifying some id's:
In the Mongo Shell it is:
db.fps.find({"_id": {$in: [15,24] }}, {someArray: {$elemMatch: {Timestamp: {$gt: "2018-06-06T18:00:00", $lt:"2018-06-07"}}}}).pretty()
Because of $elemMatch, it returns only the first document that matches my query.
However, I want all relevant documents returned that match the criteria.
How would I have to do the query in mongoose?
Let's say you have a document like this:
db.fps.save({_id: 15, someArray: [ { Timestamp: "2018-06-06T19:00:00" }, { Timestamp: "2018-06-06T19:00:00" }, { Timestamp: "2018-06-07T00:00:00" } ]});
To filter nested array you need aggregation framework, where $match will represent your matching condition and $filter will apply Timestamps comparison. $addFields simply overwrites someArray in result set here
db.fps.aggregate([
{
$match: { "_id": {$in: [15,24] } }
},
{
$addFields: {
someArray: {
$filter: {
input: "$someArray",
as: "doc",
cond: {
$and: [
{ $gt: [ "$$doc.Timestamp", "2018-06-06T18:00:00" ] },
{ $lt: [ "$$doc.Timestamp", "2018-06-07" ] }
]
}
}
}
}
}
])

mongodb find largest key inside an item in mongodb

I have a mongodb collection that has the following schema
{
_id: ,
data: {
1: {
values: ...
},
3: {
values: ...
}
2: {
values: ...
}
}
}
and I wanted to know if it would be possible to sort the items inside the data object or pick the highest values using core mongodb instead of retrieving them and sorting using javascript.
Please read #NeilLunn's comments to the question first
The "possible" yet "impractical" pipeline could be like following:
db.collection.aggregate([
{$project: {
data: { $objectToArray: "$data" }
}},
{$unwind: "$data"},
{$sort: {_id:1, "data.k":-1}},
{$group: {_id:"$_id", data:{$first:"$data"}}},
{$group: {_id:"$_id", data:{$push:"$data"}}},
{$project: {
_id: 1,
data: { $arrayToObject: "$data" }
}}
])