Mongodb creating alias in a query - mongodb

What is the mongodb's equivalent to this query:
SELECT "foo" as bar, id as "spec" from tablename

It is possible to create new field with given name and value taken from another field with $project:
{
"_id" : 1,
title: "abc123",
isbn: "0001122223334",
author: { last: "zzz", first: "aaa" },
copies: 5
}
The following $project stage adds the new fields isbn, lastName, and copiesSold:
db.books.aggregate(
[
{
$project: {
title: 1,
isbn: {
prefix: { $substr: [ "$isbn", 0, 3 ] },
group: { $substr: [ "$isbn", 3, 2 ] },
publisher: { $substr: [ "$isbn", 5, 4 ] },
title: { $substr: [ "$isbn", 9, 3 ] },
checkDigit: { $substr: [ "$isbn", 12, 1] }
},
lastName: "$author.last",
copiesSold: "$copies"
}
}
]
)
http://docs.mongodb.org/manual/reference/operator/aggregation/project/#pipe._S_project

You can use any operator like toUpper or toLower or concat or any other operator you feel like which you think you can work on and create an alias.
Example:
In the following example created_time is a field in the collection.
(I am not good with syntax so you can correct it, but this is the approach)
{$project {
"ALIAS_one" : {"$concat" : "$created_time"},
"ALIAS_two" : {"$concat" : "$created_time"},
"ALIAS_three" : {"$concat" : "$created_time"}
}}
So using an operator in that fashion you can create as many as aliases as your like.

you can use this, maybe help
database data
{ "_id" : "5ab0f445edf197158835be63", "userid" : "5aaf15c28264ee17fe869ad8", "lastmodified" : ISODate("2018-03-21T07:04:41.735Z") }
{ "_id" : "5ab0f445edf197158835be64", "userid" : "5aaf15c28264ee17fe869ad8", "lastmodified" : ISODate("2018-02-20T12:31:08.896Z") }
{ "_id" : "5ab0f445edf197158835be65", "userid" : "5aaf15c28264ee17fe869ad7", "lastmodified" : ISODate("2018-02-20T02:31:08.896Z") }
mongo command
db.zhb_test.aggregate(
[{
$group: {
_id: {
$dateToString: {
format: "%Y-%m",
date: "$lastmodified"
}
},
count: {
$sum: 1
}
}
},
{
$project: {
"month": "$_id",
count: 1,
"_id": 0
}
}])
result
{ "count" : 2, "month" : "2018-02" }
{ "count" : 1, "month" : "2018-03" }

Related

Count by elements in list and by field

I have a MongoDB collection that looks like this:
{ "_id" : 1, "owner" : "Alice", airline: "RSAirlines", "content" : ["shoes", "pants", "sockets"]}
{ "_id" : 2, "owner" : "Bob", airline: "RSAirlines", "content" : ["phone", "pants"]}
{ "_id" : 3, "owner" : "Charlie", airline: "RSAirlines", "content" : ["shoes", "pants", "bag"]}
{ "_id" : 4, "owner" : "Mary" ,airline: "AirES" "content" : ["sandals", "coins", "sockets"]}
{ "_id" : 5, "owner" : "Olivia", airline: "AirES", "content" : ["gloves", "pants", "sockets"]}
{ "_id" : 6, "owner" : "Dan", airline: "AirES", "content" : ["sockets", "wallet"]}
{ "_id" : 7, "owner" : "Erin", airline: "AirES", "content" : ["pants", "sockets", "dress"]}
I would like to aggregate them to get the following results:
{ "_id": "RSAirlines", "counts": {
"shoes": 2,
"pants": 3,
"sockets": 1,
"phone": 1,
"bag": 1
}}
{ "_id": "AirES", "counts": {
"sandals": 1,
"coins": 1,
"sockets": 4,
"wallet": 1,
"dress": 1,
"pants": 2
}}
Previous I saw this answer for counting the elements, but now I would like to count them by airline.
$unwind deconstruct content array
$group by airline and content and get the total count
$group by the only airline and construct counts array key-value format
$arrayToObject convert key-value array to object
db.collection.aggregate([
{ $unwind: "$content" },
{
$group: {
_id: {
airline: "$airline",
content: "$content"
},
count: { $sum: 1 }
}
},
{
$group: {
_id: "$_id.airline",
counts: {
$push: {
k: "$_id.content",
v: "$count"
}
}
}
},
{ $project: { counts: { $arrayToObject: "$counts" } } }
])
Playground

MongoDB Aggregation with match shows all the records

I have json object as following.
{
"_id" : ObjectId("123209sfekjern"),
"Name" : "Test1",
"Orders" : [
{
"Date" : "2020-05-05",
"Total" : "100.00"
},
{
"Date" : "2020-05-10",
"Total" : "110.00"
},
{
"Date" : "2020-05-11",
"Total" : "100.00"
},
{
"Date" : "2020-05-14",
"Total" : "110.00"
},
{
"Date" : "2020-05-20",
"Total" : "100.00"
},
{
"Date" : "2020-05-15",
"Total" : "100.00"
},
{
"Date" : "2020-05-12",
"Total" : "110.00"
},
{
"Date" : "2020-05-18",
"Total" : "100.00"
},
{
"Date" : "2020-05-31",
"Total" : "110.00"
}
]
}
I need customername, orders.Date and Order.Total for all the orders which is greater than 100.00
I tried following query..
db.Customers.aggregate
(
[
{
$match: {
$and: [
{"Orders.Date":{$gte:"2020-05-15"}},//ISODate('2020-05-15 10:00:00.000Z')
{ "Orders.Total": { $gte: "100.00" } },
]
}
},
{ $project: { _id:0, Name: 1, "Orders.Total": 1, "Orders.Date": 1} },
]
)
The above query returns all the records. I m still beginner and learning mongodb.
any help would be appreciated.
thank you.
$match filters on a document level so entire document will be returned if at least one subdocument matches your conditions. In order to filter a nested array you need $filter:
db.Customers.aggregate([
{
$project: {
_id: 0,
Name: 1,
Orders: {
$filter: {
input: "$Orders",
cond: {
$and: [
{ $gte: [ "$$this.Date", "2020-05-15" ] },
{ $gte: [ "$$this.Total", "100.00" ] },
]
}
}
}
}
}
])
Mongo Playground

Mongodb find maximum scored student embeddded array

I am new in mongodb ,Please help me out
I have more than 500 students details like this..
{
"_id" : 7,
"name" : "Salena Olmos",
"scores" : [
{
"score" : 90.37826509157176,
"type" : "exam"
},
{
"score" : 42.48780666956811,
"type" : "quiz"
},
{
"score" : 96.52986171633331,
"type" : "homework"
}
]
},
/* 2 */
{
"_id" : 8,
"name" : "Daphne Zheng",
"scores" : [
{
"score" : 22.13583712862635,
"type" : "exam"
},
{
"score" : 14.63969941335069,
"type" : "quiz"
},
{
"score" : 75.94123677556644,
"type" : "homework"
}
]
}
Need to find one student details who got highest marks in "type" exam
Output as follows...
{
"_id" : 7,
"name" : "Salena Olmos",
"scores" : [
{
"score" : 90.37826509157176,
"type" : "exam"
},
{
"score" : 42.48780666956811,
"type" : "quiz"
},
{
"score" : 96.52986171633331,
"type" : "homework"
}
]
}
I need one student details from whole collection. The problem I am facing that need to search in embedded array "score" as well as "type".
Someone please help me
Try this
db.collection.aggregate([
{
$group: {
_id: "$_id",
scores: {
$first: "$scores"
},
data: {
$push: "$$ROOT"
}
}
},
{
$unwind: "$data"
},
{
$match: {
"data.scores.type": "exam"
}
},
{
$sort: {
"data.scores.score": -1
}
},
{
$project: {
_id: 1,
name: "$data.name",
scores: "$scores"
}
},
{
$limit: 1
}
])
Sample Playground
While this doesn't answer the question, it is related. This one filters out all the subdocuments which match the conditions "greater or equal 90" and type "exam"
db.collection.aggregate([
{
$match: {
"scores.score": {
$gte: 90
},
"scores.type": "exam"
}
},
{
$project: {
name: true,
list: {
$filter: {
input: "$scores",
as: "list",
cond: {
$and: [
{
$gt: [
"$$list.score",
90
]
},
{
$eq: [
"$$list.type",
"exam"
]
}
]
}
}
}
}
}
])
which returns
[
{
"_id": 7,
"list": [
{
"score": 90.37826509157176,
"type": "exam"
}
],
"name": "Salena Olmos"
}
]
https://mongoplayground.net/p/hYnVzZbuNFI
If you want the entire document, then add doc: "$$ROOT", to the projection.

MongoDB aggregate array of objects together by object id and count occurences

I'm trying to figure out what I'm doing wrong, I have collected the following, "Subset of data", "Desired output"
This is how my data objects look
[{
"survey_answers": [
{
"id": "9ca01568e8dbb247", // As they are, this is the key to groupBy
"option_answer": 5, // Represent the index of the choosen option
"type": "OPINION_SCALE" // Opinion scales are 0-10 (meaning elleven options)
},
{
"id": "ba37125ec32b2a99",
"option_answer": 3,
"type": "LABELED_QUESTIONS" // Labeled questions are 0-x (they can change it from survey to survey)
}
],
"survey_id": "test"
},
{
"survey_answers": [
{
"id": "9ca01568e8dbb247",
"option_answer": 0,
"type": "OPINION_SCALE"
},
{
"id": "ba37125ec32b2a99",
"option_answer": 3,
"type": "LABELED_QUESTIONS"
}
],
"survey_id": "test"
}]
My desired output is:
[
{
id: '9ca01568e8dbb247'
results: [
{ _id: 5, count: 1 },
{ _id: 0, count: 1 }
]
},
{
id: 'ba37125ec32b2a99'
results: [
{ _id: 3, count: 2 }
]
}
]
Active query
Model.aggregate([
{
$match: {
'survey_id': survey_id
}
},
{
$unwind: "$survey_answers"
},
{
$group: {
_id: "$survey_answers.option_answer",
count: {
$sum: 1
}
}
}
])
Current output
[
{
"_id": 0,
"count": 1
},
{
"_id": 3,
"count": 2
},
{
"_id": 5,
"count": 1
}
]
I added your records to my db. Post that I tried your commands one by one.
$unwind results you similar to -
> db.survey.aggregate({$unwind: "$survey_answers"})
{ "_id" : ObjectId("5c3859e459875873b5e6ee3c"), "survey_answers" : { "id" : "9ca01568e8dbb247", "option_answer" : 5, "type" : "OPINION_SCALE" }, "survey_id" : "test" }
{ "_id" : ObjectId("5c3859e459875873b5e6ee3c"), "survey_answers" : { "id" : "ba37125ec32b2a99", "option_answer" : 3, "type" : "LABELED_QUESTIONS" }, "survey_id" : "test" }
{ "_id" : ObjectId("5c3859e459875873b5e6ee3d"), "survey_answers" : { "id" : "9ca01568e8dbb247", "option_answer" : 0, "type" : "OPINION_SCALE" }, "survey_id" : "test" }
{ "_id" : ObjectId("5c3859e459875873b5e6ee3d"), "survey_answers" : { "id" : "ba37125ec32b2a99", "option_answer" : 3, "type" : "LABELED_QUESTIONS" }, "survey_id" : "test" }
I am not adding code for match since that is okay in your query as well
The grouping would be -
> db.survey.aggregate({$unwind: "$survey_answers"},{$group: { _id: { 'optionAnswer': "$survey_answers.option_answer", 'id':"$survey_answers.id"}, count: { $sum: 1}}})
{ "_id" : { "optionAnswer" : 0, "id" : "9ca01568e8dbb247" }, "count" : 1 }
{ "_id" : { "optionAnswer" : 3, "id" : "ba37125ec32b2a99" }, "count" : 2 }
{ "_id" : { "optionAnswer" : 5, "id" : "9ca01568e8dbb247" }, "count" : 1 }
You can group on $survey_answers.id to bring it into projection.
The projection is what you're missing in your query -
> db.survey.aggregate({$unwind: "$survey_answers"},{$group: { _id: { 'optionAnswer': "$survey_answers.option_answer", 'id':'$survey_answers.id'}, count: { $sum: 1}}}, {$project : {answer: '$_id.optionAnswer', id: '$_id.id', count: '$count', _id:0}})
{ "answer" : 0, "id" : "9ca01568e8dbb247", "count" : 1 }
{ "answer" : 3, "id" : "ba37125ec32b2a99", "count" : 2 }
{ "answer" : 5, "id" : "9ca01568e8dbb247", "count" : 1 }
Further you can add a group on id and add results to a set. And your final query would be -
db.survey.aggregate(
{$unwind: "$survey_answers"},
{$group: {
_id: { 'optionAnswer': "$survey_answers.option_answer", 'id':'$survey_answers.id'},
count: { $sum: 1}
}},
{$project : {
answer: '$_id.optionAnswer',
id: '$_id.id',
count: '$count',
_id:0
}},
{$group: {
_id:{id:"$id"},
results: { $addToSet: {answer: "$answer", count: '$count'} }
}},
{$project : {
id: '$_id.id',
answer: '$results',
_id:0
}})
Hope this helps.

MongoDB aggregate group array to key : sum value

Hello I am new to mongodb and trying to convert objects with different types (int) into key value pairs.
I have collection like this:
{
"_id" : ObjectId("5372a9fc0079285635db14d8"),
"type" : 1,
"stat" : "foobar"
},
{
"_id" : ObjectId("5372aa000079285635db14d9"),
"type" : 1,
"stat" : "foobar"
},
{
"_id" : ObjectId("5372aa010079285635db14da"),
"type" : 2,
"stat" : "foobar"
},{
"_id" : ObjectId("5372aa030079285635db14db"),
"type" : 3,
"stat" : "foobar"
}
I want to get result like this:
{
"type1" : 2, "type2" : 1, "type3" : 1,
"stat" : "foobar"
}
Currently trying aggregation group and then push type values to array
db.types.aggregate(
{$group : {
_id : "$stat",
types : {$push : "$type"}
}}
)
But don't know how to sum different types and to convert it into key values
/* 0 */
{
"result" : [
{
"_id" : "foobar",
"types" : [
1,
2,
2,
3
]
}
],
"ok" : 1
}
For your actual form, and therefore presuming that you actually know the possible values for "type" then you can do this with two $group stages and some use of the $cond operator:
db.types.aggregate([
{ "$group": {
"_id": {
"stat": "$stat",
"type": "$type"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.stat",
"type1": { "$sum": { "$cond": [
{ "$eq": [ "$_id.type", 1 ] },
"$count",
0
]}},
"type2": { "$sum": { "$cond": [
{ "$eq": [ "$_id.type", 2 ] },
"$count",
0
]}},
"type3": { "$sum": { "$cond": [
{ "$eq": [ "$_id.type", 3 ] },
"$count",
0
]}}
}}
])
Which gives exactly:
{ "_id" : "foobar", "type1" : 2, "type2" : 1, "type3" : 1 }
I actually prefer the more dynamic form with two $group stages though:
db.types.aggregate([
{ "$group": {
"_id": {
"stat": "$stat",
"type": "$type"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.stat",
"types": { "$push": {
"type": "$_id.type",
"count": "$count"
}}
}}
])
Not the same output but functional and flexible to the values:
{
"_id" : "foobar",
"types" : [
{
"type" : 3,
"count" : 1
},
{
"type" : 2,
"count" : 1
},
{
"type" : 1,
"count" : 2
}
]
}
Otherwise if you need the same output format but need the flexible fields then you can always use mapReduce, but it's not exactly the same output.
db.types.mapReduce(
function () {
var obj = { };
var key = "type" + this.type;
obj[key] = 1;
emit( this.stat, obj );
},
function (key,values) {
var obj = {};
values.forEach(function(value) {
for ( var k in value ) {
if ( !obj.hasOwnProperty(k) )
obj[k] = 0;
obj[k]++;
}
});
return obj;
},
{ "out": { "inline": 1 } }
)
And in typical mapReduce style:
"results" : [
{
"_id" : "foobar",
"value" : {
"type1" : 2,
"type2" : 1,
"type3" : 1
}
}
],
But those are your options
Is this close enough for you?
{ "_id" : "foobar", "types" : [ { "type" : "type3", "total" : 1 }, { "type" : "type2", "total" : 1 }, { "type" : "type1", "total" : 2 } ] }
The types are in an array, but it seems to get you the data you are looking for. Code is:
db.types.aggregate(
[{$group : {
_id : "$stat",
types : {$push : "$type"}
}},
{$unwind:"$types"},
{$group: {
_id:{stat:"$_id",
types: {$substr: ["$types", 0, 1]}},
total:{$sum:1}}},
{$project: {
_id:0,
stat:"$_id.stat",
type: { $concat: [ "type", "$_id.types" ] },
total:"$total" }},
{$group: {
_id: "$stat",
types: { $push: { type: "$type", total: "$total" } } }}
]
)