This question already has answers here:
how to get the max value of a field in MongoDB
(2 answers)
mongodb how to get max value from collections
(9 answers)
MongoDB find and return all with max value
(1 answer)
Closed 2 years ago.
I am working on a query to find the subject title, subject type, and credit value of subject with highest credit value. This is the query I have come up with:
db.Subject.aggregate([{$match:{"subject.credit":{$max:true}},
{$project:{"subject.subTitle":1, "subject.type":1, "subject.credit":1, _id: 0}}
]).pretty()
This doesn't seem to net anything.
and
db.Subject.aggregate([{$match:{"subject.credit":$max}},
$project:{"subject.subTitle":1, "subject.type":1, "subject.credit":1, _id: 0}}
]).pretty()
This nets and error as shown below:
E QUERY [js] ReferenceError: $max is not defined :
#(shell):1:32
Here is a part of the database that contains the highest credit value:
db.Subject.insert(
{
"_id":ObjectId(),
"subject":{
"subCode":"CSCI321",
"subTitle":"Final Year Project",
"credit":6,
"type":"Core",
"assessments": [
{ "assessNum": 1,
"weight":30,
"assessType":"Presentation",
"description":"Prototype demonstration" },
{ "assignNum": 2,
"weight":70,
"assessType":"Implementation and Presentation",
"description":"Final product Presentation and assessment of product implementation by panel of project supervisors" }
]
}
}
)
A good strategy, if you don't have an index, is to collapse all documents and get one value:
const pipeline = [
{
"$project" : {
"subTitle" : "$subject.subTitle",
"type" : "$subject.type",
"credit" : "$subject.credit",
"_id" : 0
}
},
{
"$sort" : {
"credit" : -1
}
},
{
"$limit" : 1
}
]
db.Subject.aggregate(pipeline)
Query
$project We want only a subset of fields
$sort to get the highest credit first.
$limit:1 to get only the highest.
db.Subject.find({},{"subject.subTitle":1, "subject.type":1, "subject.credit":1,"_id":0}).sort({"subject.credit":-1})
just use this
Related
This question already has answers here:
compare two fields of same document [duplicate]
(1 answer)
MongoDb query condition on comparing 2 fields
(4 answers)
Closed 3 years ago.
This is the result of an aggregate query,
{
"_id" : ObjectId("5dab3240dfbe9a15cd69771d"),
"isManual" : false,
"frequency" : 60,
"lastExecuted" : ISODate("2019-10-21T03:38:15.114Z"),
"lastExecutedTimeFromNow" : 129.58105
}
{
"_id" : ObjectId("5dad47c65310a16581cc6294"),
"isManual" : false,
"frequency" : 50,
"lastExecuted" : ISODate("2019-10-25T00:00:00.000Z"),
"lastExecutedTimeFromNow" : 100
}
{
"_id" : ObjectId("5dad48a55310a16581cc6332"),
"isManual" : true,
"frequency" : 100,
"lastExecuted" : ISODate("2019-10-23T00:00:00.000Z"),
"lastExecutedTimeFromNow" : 50
}
I wanted to filter the documents where the field lastExecutedTimeFromNow greater than frequency. But it returns 0 results.
Here's the aggregate query I'm using,
db.getCollection('test').aggregate([
{
$match: {
"lastExecutedTimeFromNow": { $gte: "$frequency" }
}
}
])
Any clue on where I'm going wrong or any help on this would really be great.
You can use $expr but keep in mind it's slower than normal $match
db.getCollection('test').aggregate([
{
$match: {
$expr: {
$gte: [
"$lastExecutedTimeFromNow",
"$frequency"
]
}
}
}
])
This question already has answers here:
Mongodb sort inner array
(3 answers)
MongoDB group by array inner-elements
(1 answer)
Closed 3 years ago.
I would like to do aggregation by using $project to query array of objects to get single field data and store as array in descending order or reverse array. I had searched for some solutions at stackoverflow but did not see questions with project query then reverse array.
For example below is my mock data:
"models" : [
{
"model" : "abc002",
"total_modules" : 2
},
{
"model" : "abc003",
"total_modules" : 2
},
{
"model" : "abc004",
"total_modules" : 2
},
]
I have tried with the below solution but it is not exactly what I want as the output is slightly different as shown below:
db.collection.aggregate([
{$project: {"models.model":1}}
])
Output:
"models" : [
{
"model" : "abc002"
},
{
"model" : "abc003"
},
{
"model" : "abc004"
}
]
**In fact, I would like to get this output:**
{
models: [ abc004, abc003, abc002 ]
}
OR
{
models: [ {model:abc004}, {model:abc003}, {model:abc002} ]
}
This question already has answers here:
Mongo field A greater than field B
(4 answers)
Closed 5 years ago.
I want to get records of a MongoDB collection that sticks to this condition: fieldA > fieldB + someNaturalValue. This is what I tried so far:
db.getCollection('collection').find({
$where: function() {
return this.fieldA > this.fieldB + 10000}
});
// or
db.getCollection('collection').aggregate([
{ "$project" : {
"sum" : {"$add" : ["$fieldB", 10000]}
}
},
{ "$match" : {
"sum" : {"$lte" : "$fieldA"}
}
}
]);
The issue I face here is the extra value that I need to add in the condition to one of the fields. Those are not working, that value is not taken into account. What I am missing? I appreciate any kind of help.
Sample Data
db.collection.insert({fieldA : 21000, fieldB : 10000}); //1 ok
db.collection.insert({fieldA : 15000, fieldB : 8000}); //2 nok
db.collection.insert({fieldA : 24000, fieldB : 22000}); //3 nok
db.collection.insert({fieldA : 22000, fieldB : 1000}); //4 ok
Adjusted code from the duplicated question:
db.collection.aggregate([
{$project: {
cmp_value: {$cmp: ['$fieldA', {$add: ['$fieldB', 10000]}]},
obj: '$$ROOT'
}},
{$match: {cmp_value: {$gt: 0}}},
{ $replaceRoot: { newRoot: '$obj' } }
])
$where should be avoided where possible. Documentation is quite clear about it:
The $where provides greater flexibility, but requires that the database processes the JavaScript expression or function for each document in the collection
This question already has answers here:
Query for documents where array size is greater than 1
(14 answers)
Closed 7 years ago.
Example document:
{
"aliases" : {
"name" : [
"Brinton McKay",
"Dr. Theopolis",
"Galactic Spiral Sound",
"Highrise",
"Memory Boy",
"Semblance Factor",
"Spy (2)",
"Three O'Clock High"]}
}
How i can count the number of "name" under "aliases"?
I would like to print all _id who which contains more than 3 aliases.
any help would be appreciated.
Please check the below query :
db.collection.find({ $where : function()
{ return Object.keys(this.aliases.name).length > 3 } });
OR
db.collection.aggregate([
{$project : { _id :1 , numb : {$size : "$aliases.name"} }
},
{$match : { numb :{$gt : 3 }}
}
]);
PS : you can see the documentation in below link :
http://docs.mongodb.org/manual/reference/operator/query/where/
I have a document with sub-document which looks something like:
{
"name" : "some name1"
"like" : [
{ "date" : ISODate("2012-11-30T19:00:00Z") },
{ "date" : ISODate("2012-12-02T19:00:00Z") },
{ "date" : ISODate("2012-12-01T19:00:00Z") },
{ "date" : ISODate("2012-12-03T19:00:00Z") }
]
}
Is it possible to fetch documents "most liked" (average value for the last 7 days) and sort by the count?
There are a few different ways to solve this problem. The solution I will focus on uses mongodb's aggregation framework. First, here is an aggregation pipeline that will solve your problem, following it will be an explanation/breakdown of what is happening in the command.
db.testagg.aggregate(
{ $unwind : '$likes' },
{ $group : { _id : '$_id', numlikes : { $sum : 1 }}},
{ $sort : { 'numlikes' : 1}})
This pipeline has 3 main commands:
1) Unwind: this splits up the 'likes' field so that there is 1 'like' element per document
2) Group: this regroups the document using the _id field, incrementing the numLikes field for every document it finds. This will cause numLikes to be filled with a number equal to the number of elements that were in "likes" before
3) Sort: Finally, we sort the return values in ascending order based on numLikes. In a test I ran the output of this command is:
{"result" : [
{
"_id" : 1,
"numlikes" : 1
},
{
"_id" : 2,
"numlikes" : 2
},
{
"_id" : 3,
"numlikes" : 3
},
{
"_id" : 4,
"numlikes" : 4
}....
This is for data inserted via:
for (var i=0; i < 100; i++) {
db.testagg.insert({_id : i})
for (var j=0; j < i; j++) {
db.testagg.update({_id : i}, {'$push' : {'likes' : j}})
}
}
Note that this does not completely answer your question as it avoids the issue of picking the date range, but it should hopefully get you started and moving in the right direction.
Of course, there are other ways to solve this problem. One solution might be to just do all of the sorting and manipulations client-side. This is just one method for getting the information you desire.
EDIT: If you find this somewhat tedious, there is a ticket to add a $size operator to the aggregation framework, I invite you to watch and potentially upvote it to try and speed to addition of this new operator if you are interested.
https://jira.mongodb.org/browse/SERVER-4899
A better solution would be to keep a count field that will record how many likes for this document. While you can use aggregation to do this, the performance will likely be not very good. Having a index on the count field will make read operation fast, and you can use atomic operation to increment the counter when inserting new likes.
You can use this simplify the above aggregation query by the following from mongodb v3.4 onwards:
> db.test.aggregate([
{ $unwind: "$like" },
{ $sortByCount: "$_id" }
]).pretty()
{ "_id" : ObjectId("5864edbfa4d3847e80147698"), "count" : 4 }
Also as #ACE said you can now use $size within a projection instead:
db.test.aggregate([
{ $project: { count: { $size : "$like" } } }
]);
{ "_id" : ObjectId("5864edbfa4d3847e80147698"), "count" : 4 }