Mongo DB aggregation array size greater than match [duplicate] - mongodb

This question already has answers here:
Query for documents where array size is greater than 1
(14 answers)
Closed 5 years ago.
I have a collection where investments is an array inside the mongodb document. Now using aggregation I am trying to filter results where investments length is more than 5 times and then do the next processing using match query.
Collection{
_id:000000
---------------------
"investments" : [ {
hhhhhhhhhhhhhh
},
{
hhhhhhhhhhhhhh
} }]
-----------------
The match query I wrote like below which isn't working. Any suggestions:
db.companies.aggregate( [
{ $match: {"founded_year" : 2004},
{ "investments" : {$size: : { $gte: 5 } } } },
----------------------------------
--------------------------------
]}

With aggregate:
db.companies.aggregate([
{ $match: { "founded_year":2004 } },
{ $project: { founded_year:1,
moreThanFive: { $gt: [ {$size: "$external_links" }, 5 ] } } },
{ $match: { moreThanFive : true }} ,
])
You will need to:
1. Include a $project stage, to find the number of investement (the size of the array), and check if that greater than 5.
2. and then do another $match stage to filter those with moreThanFive equals to true.
With find:
db.companies.find({'investments.5': {$exists: true}})
You ask if the position number 6 in the investments array exists.

Related

mongodb - How to get two counts from one query without putting them in an array [duplicate]

This question already has answers here:
Multiple Counts with single query in mongodb
(3 answers)
Closed 2 years ago.
I have a comments collection with two fields - "up" and "down". Right now, I use only one of them to get the count using query below:
$lookup: {
from: "votesComments",
as: "commentVotes",
let: {
commentI: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$commentId",
"$$commentI"
]
},
}
},
{
"$group" : {_id:"$up", count:{$sum:1}}
},
]
}
},
The result is:
0: {_id: 1, count: 2} ====> id = 1 is when "up" field has 1. Total up votes is 2
1: {_id: 0, count: 1} ====> id = 0 is when "up" field has 0. Total down votes is 1
This is an array. When I unwind it, I only get
{_id: 1, count: 2}
I need to do one of the following:
Get the results in a simple format - {upvotes: 2, downvotes: 1}
OR
Unwind the result to include both [0] and [1] elements of the resulting array.
OR
Is it possible to perform two counts in one query? [Count number of 1s in Up and number of 1s in Down fields?
This did it
"$group": {
"_id": "null",
"upCount": { "$sum": "$up" },
"downCount": { "$sum": "$down" }
},

Is there way to skip different find filter output in one query MongoDB

Is that possible to skip the first record in a document by name For eg product_detail is the collection and it has 10 documents with name apple and 10 documents in name mango can I skip the first 2 documents in each? The below query for skipping the first 2 documents in apple.
Query :
db.getCollection('product_detail').find({"productInfo.name" : "apple"}).skip(2);
db.getCollection('product_detail').find({"productInfo.name" : "mango"}).skip(2);
Instead of two queries to skip 2 documents for "productInfo.name": "apple" and "productInfo.name": "mango" I need one Can anyone help me out?
Check out $facet aggregation pipeline stage
db.getCollection('product_detail').aggregate([{
$facet: {
apple: [
{
$match: { "productInfo.name": "apple" }
},
{
$sort: {/* your sort condition here to ensure order */} }]
},
{
$skip: 2
}
],
mango: [
{
$match: { "productInfo.name": "mango" }
},
{
$sort: {/* your sort condition here to ensure order */} }]
},
{
$skip: 2
}
]
}
}])

MongoDB, finding documents by matching sub elements in an array by several Date conditions [duplicate]

This question already has answers here:
Specify Multiple Criteria for Array Elements
(2 answers)
MongoDB: find value in Array with multiple criteria
(1 answer)
Closed 3 years ago.
I have documents like this:
{
"_id": ID,
"seen_at" : [
ISODate("2018-12-27T17:00:00.000Z"),
ISODate("2019-01-01T01:00:00.000Z")
]
}
I try to select document based on a query into the seen_at elements:
db.collection.aggregate(
[
{
"$match": {
seen_at: {
"$gt": ISODate("2019-01-01T00:00:00.000Z"),
"$lt": ISODate('2019-01-01T00:00:00.001Z')
}
}
}
]
)
I was expecting this query to find only documents that have elements in the seen_at that matche both conditions.
But the above query returns the top-above document (among others also not matching both conditions)
Use $elemMatch if you have multiple criteria to find from array:
db.collection.find({
seen_at: {
$elemMatch: {
"$gt": ISODate("2019-01-01T00:00:00.000Z"),
"$lt": ISODate("2019-01-01T00:00:00.001Z")
}
}
})
Checkout the results in Mongo Playground for find.
If you have to use Aggregate, the $unwind operator can be used:
db.collection.aggregate([
{
$unwind : "$seen_at"
},
{
"$match": {
seen_at: {
"$gt": ISODate("2019-01-01T00:00:00.000Z"),
"$lt": ISODate('2019-01-01T00:00:00.001Z')
}
}
},
{
$group : {
"_id" : "$_id",
"seen_at" : {$push : "$seen_at"}
}
}
])
Checkout the results in Mongo Playground for Aggregate.

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" ] }
]
}
}
}
}
}
])

Return MongoDB/Mongoose Aggregation Match First Letter [duplicate]

This question already has answers here:
How to query MongoDB with "like"
(45 answers)
Closed 5 years ago.
I am trying to return an array of results using Mongoose and mongoDB in Node.js.
I have something like this to match every header that starts with za for example:
Model.aggregate(
{ $project: { firstLetter : { $substr : ["$header", 0, 2] }}},
{ $match: { firstLetter : 'za' }},
{ $limit: 40 }
);
But when I assign the result to a variable it is just an Aggregate object that I cannot identify what to do with.
Mongoose docs state:
The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).
Why am I not getting the results?
Turns out that you need to get the data asynchronously, which makes sense (of course).
Something like:
Model.aggregate(
{ $project: { firstLetter : { $substr : ["$header", 0, 2] }}},
{ $match: { firstLetter : 'za' }},
{ $limit: 40 }
).exec(function(err, data) {
doSomethingWithData(data);
});
Hopefully can help someone else out.