Retrieve Array Of Documents in MongoDB - mongodb

I have a MongoDB Document like as follows
{
"_id":1,
"name":"XYZ"
ExamScores:[
{ExamName:"Maths", UnitTest:1, Score:100},
{ExamName:"Maths", UnitTest:2, Score:80},
{ExamName:"Science", UnitTest:1, Score:90}
]
}
I Need to retrieve this document so that it has to show only Maths Array. Like as follows
{
"_id":1,
"name":"XYZ"
ExamScores:[
{ExamName:"Maths", UnitTest:1, Score:100},
{ExamName:"Maths", UnitTest:2, Score:80},
]
}
How Can I Do That ?

As #karin states there is no, normal, in query method of doing this.
In version 2.2 you can use $elemMatch to project the first matching result from ExamScores but you cannot get multiple.
That being said, the aggregation framework can do this:
db.col.aggregate([
{$unwind: '$ExamScores'},
{$match: {'ExamScores.ExamName':"Maths"}},
{$group: {_id: '$_id', name: '$name', ExamScores: {$push: '$ExamScores'}}}
])
Something like that anyway.

This has been asked before MongoDB query to limit values based on condition, the only answer there says it is not possible, but that there is a request to implement that.

Related

Aggregate method in MongoDB Compass?

as stated in the title i'm having some problems querying from MongoDB Compass using the aggregate methhod. I have a collection of documents in this form:
{"Array":[{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},...]}
using mongo shell or Studio 3T software I query it with aggregate method, follows an example:
db.collection.aggregate([
{ $match: {"Array.field": "val"}},
{ $unwind: "$Array"},
{ $match: {"Array.field": "val"}},
{ $group: {_id: null, count: {$sum:NumberInt(1)}, Array: {$push: "$Array"}}},
{ $project: {"N. Hits": "$count", Array:1}}
])
where I look for elements of Array who has field's value = "val" and count them. This works perfectly, but I don't know how to do the same in MongoDB Compass
in the query bar I have 'filter', 'project' and 'sort' and I can do usual queries, but i don't know how to use aggregate method.
Thanks
You are looking at the Documents tab which is restricted for querying documents.
Take a look in the second tab called Aggregations where you can do your aggregation pipelines, as usual.
For further information please visit the Aggregation Pipeline Builder documentation.

How do I project an element of an array in mongo?

I have a mongo document that contains something like
{date: [2018, 3, 22]}
and when I try to project this into a flat JSON structure with these fields concatenated, I always get an array with 0 elements, eg. just extracting the year with
db.getCollection('blah').aggregate([
{$project: {year: "$date.0"}}
])
I get
{"year" : []}
even though matching on a similar expression works fine, eg.
db.getCollection('blah').aggregate([
{$match: {"$date.0": 2018}}
])
selects the documents I would expect just fine.
What am I doing wrong? I've searched mongo documentation and stackoverflow but could find nothing.
For $project you should use $arrayElemAt instead of dot notation which works only for queries.
db.getCollection('blah').aggregate([
{$project: {year: { $arrayElemAt: [ "$date", 0 ] }}}
])
More here

$project multiple fields into one field

I'm working with MongoDB 3.0 (we won't be upgrading until next year.) I have a requirement to get a list of unique values across multiple fields in a collection. The fields have the same value most of the time. This can be accomplished in version 3.2 by something like this:
db.mydata.aggregate([
{'$project': {'combined_users': ['$user1', '$user2']}},
{'$unwind': '$combined_users'},
{'$group': {_id: 1, {$addToSet: '$combined_users'}}}
The issue is in version 3.0 we get "disallowed field type Array in..." at the combined_data.
How do I accomplish the same thing in Mongo 3.0?
You need to use the $setUnion operator
db.mydata.aggregate([
{'$project': { 'combined_users': { "$setUnion": ['$user1', '$user2'] }}}
])

mongo find limit each match

I have a mongo collection which looks something like this:
{
title: String,
category: String
}
I want to write a query that selects various categories, similar to this:
Collection.find({category: {$in: ['Books', 'Cars', 'People']});
But I want to only select a limited number of each category, for example 5 of each book, car, people. How do I write such a query? Can I do it one query or must I use multiple ones?
You can do it using mongodb aggregation. Take a look at this pipeline:
Filter all documents by categories(using $match).
Group data by categories and create array for items with the same category(using $group and $push).
Get a subset of each array with a limited maximum length(using $project and $slice).
Try the following query:
db.collection.aggregate([
{$match: {category: {$in: ['Books', 'Cars', 'People']}}},
{$group: {_id: "$category", titles: {$push: "$title"}}},
{$project: {titles: {$slice: ["$titles", 5]}}}
])

Mongodb aggregation sort on array primative

Given documents like
{
...
name:'whatever',
games: [122, 199, 201, 222]
}
db.col.aggregate({$match:{}},
{$sort:{'games.0': -1}})
doesn't sort ... no errors ... it just doesn't sort on the first array element of the games array.
Although a query with the same syntac .. works fine
col.find({}).sort({'games.0':-1})
if I change the collection so games is an array of objects like
[ {game1:198}, {game2:201} ...]
then the aggregation works using
{$sort:{'games.game1': -1}})
what am I missing to get this to work with an array of numbers?
Try unwinding the array first by applying the $unwind operator on the array, then use $sort on the deconstructed array and finally use $group to get the original documents structure:
db.coll.aggregate([
{"$unwind": "$games"},
{"$sort": {"games": 1}},
{
"$group": {
"_id": "$_id",
"name": {"$first": "$name"},
"games": {"$push": "$games"}
}
}
])
Try this:
db.coll.aggregate([
{"$unwind": "$games"},
{"$sort": {"games": -1}}
]}
I hope this will work for you as you expected.
In mongo 3.4 find sort i.e. db.col.find({}).sort({'games.0':-1}) works as expected whereas aggregation sort doesn't.
In mongo 3.6 both find and aggregation sort works as expected.
Jira issue for that: https://jira.mongodb.org/browse/SERVER-19402
I would recommend you to update your mongo version and your aggregation query will work fine.