mongodb: Unable to fetch results from $project and $eq - mongodb

below code first joins two collections on one field and tries to filter values on other field.
db.zeroDimFacts.aggregate(
{$lookup:{from:"zeroDim",localField:"Kind",foreignField:"Model", as:"EmbedUp"}},
{$project: {"EmSub":"$EmbedUp.Sub","Result": {$eq:["$Type","$EmbedUp.Sub"]}, "type":"$Type"}})
Please check the below output of the code. Even though 'EmSub' & '$Type' are having equal values, it does not show up in 'Result' field.
If it is because 'EmSub' is displayed as array, how do I compare only value containing in that array?
/* 1 */
{
"_id" : NumberLong(1),
"EmSub" : [
"Fruit"
],
"Result" : false,
"type" : "Fruit"
}
/* 2 */
{
"_id" : NumberLong(2),
"EmSub" : [
"Fruit"
],
"Result" : false,
"type" : "Fruit"
}
/* 3 */
{
"_id" : NumberLong(3),
"EmSub" : [
"Fruit"
],
"Result" : false,
"type" : "Fruit"
}

You can unwind the array to compare with its elements like this:
db.zeroDimFacts.aggregate([{$lookup:{from:"zeroDim",localField:"Kind",foreignField:"Model", as:"EmbedUp"}},
{$unwind: "$EmbedUp"},
{$project: {"EmSub":"$EmbedUp.Sub","Result": {$eq:["$Type","$EmbedUp.Sub"]}, "type":"$Type"}}]);
It can give you more than one result for a single zeroDimFacts _id, however you can group them again
db.zeroDimFacts.aggregate([{$lookup:{from:"zeroDim",localField:"Kind",foreignField:"Model", as:"EmbedUp"}},
{$unwind: "$EmbedUp"},
{$project: {"EmSub":"$EmbedUp.Sub","Result": {$eq:["$Type","$EmbedUp.Sub"]}, "type":"$Type"}},
{$group: {_id: "$_id", EmSub: {$push: "$EmSub"}, Result: {$push: "$Result"}, type: {$push: "$type"}}}]);

Related

How can i access N th level of Sub Document in MongoDB

{
"_id" : ObjectId("5b4d815ad85250f4e502d142"),
"company_Name" : "Rishabh Instruments",
"spaces" : [
{
"_id" : "11",
"name" : "Trishala",
"spaces" : [
{
"_id" : "111",
"name" : "ESL"
},
{
"_id" : "112",
"name" : "IS"
}
]
},
{
"_id" : "12",
"name" : "Riddhi",
"spaces" : [
{}
]
},
{
"name" : "XYZ",
"spaces" : [
{}
]
}
]
}
This is my Document structure in Mongo DB and it may have the sub documents upto N th level so for now I want to access the document named with ESL and IS. so how can i do that i am able to go upto 2nd level with below query so
db.space.aggregate([
{$match: {company_Name: 'Rishabh Instruments'}},
{$unwind: '$spaces'},
{$match: {'spaces.name': 'Trishala'}}
// {$unwind: '$spaces'},
// {$match: {'spaces.name': 'ESL'}}
])
but if i uncomment those two lines then it doesn't return any thing
so can anyone guide me or give any hint.
I tried the below solution and its working as expected i can go to N th level by chaining the key as in my case key is spaces
db.space.aggregate([
{$match: {company_Name: 'Rishabh Instruments'}},
{$unwind: '$spaces'},
{$match: {'spaces.name': 'Trishala'}},
{$unwind: '$spaces.spaces'},
{$match: {'spaces.spaces.name': 'ESL'}}
])
Try this aggregate query with projection to match the sample output you had provided :
db.space.aggregate([
{$match: {company_Name: 'Rishabh Instruments'}},
{$unwind: '$spaces'},
{$match: {'spaces.name': 'Trishala'}},
{$unwind: '$spaces.spaces'},
{$match: {$or : [{'spaces.spaces.name': 'ESL'},{'spaces.spaces.name': 'IS'}]}},
{$project : {_id : 0, _id :'$spaces.spaces._id', name:'$spaces.spaces.name'}}
])
Output :
{ "_id" : "111", "name" : "ESL" }
{ "_id" : "112", "name" : "IS" }

Aggregation query returning array of all objects for mongodb

I'm using mongo for the first time. I'm trying to aggregate some documents in a collection using the query below. Instead the query returns an object with a key "result" that contains an array of all the documents that fit with $match.
Below is the query.
db.events_2015_04_10.aggregate([
{$group:{
_id: "$uid",
count: {$sum: 1},
},
$match : {promo:"bc40100abc8d4eb6a0c68f81f4a756c7", evt:"login"}
}
]
);
Below is a sample document in the collection:
{
"_id" : ObjectId("552712c3f92ea17426000ace"),
"product" : "Mobile Safari",
"venue_id" : NumberLong(71540),
"uid" : "dd542fea6b4443469ff7bf1f56472eac",
"ag" : 0,
"promo" : "bc40100abc8d4eb6a0c68f81f4a756c7",
"promo_f" : NumberLong(1),
"brand" : NumberLong(17),
"venue" : "ovation_2480",
"lt" : 0,
"ts" : ISODate("2015-04-10T00:01:07.734Z"),
"evt" : "login",
"mac" : "00:00:00:00:00:00",
"__ns__" : "wifipromo",
"pvdr" : NumberLong(42),
"os" : "iPhone",
"cmpgn" : "fc6de34aef8b4f57af0b8fda98d8c530",
"ip" : "192.119.43.250",
"lng" : 0,
"product_ver" : "8"
}
I'm trying to get it all grouped by uid's with the total sum of each group... What is the correct way to achieve this?
Try the following aggregation framework which has the $match pipeline stage first and then the $group pipeline later:
db.events_2015_04_10.aggregate([
{
$match: {
promo: "bc40100abc8d4eb6a0c68f81f4a756c7",
evt: "login"
}
},
{
$group: {
_id: "$uid",
count: {
$sum: 1
}
}
}
])

MongoDB query result returns an array of arrays of dictionaries. I need only an array of dictionaries

I need the value of the "browser" key in my result to be an array of dictionaries. My current query returns an array of arrays of dictionaries which is not what I want.
How would I change/modify my query to get the value of the "browser" key to be just an array of dictionaries?
Is there a better way to pass the browser data from the first group to the second group in my aggregate query?
Below is my data, my query, and my current result:
Data Format:
{
"_id" : ObjectId("52f11293ed50ed92d0324755"),
"major" : "26",
"site_domain" : "www.google.com",
"user_id" : "34850348039485093455445434",
"timestamp" : "1390953411",
"browser_name" : "Firefox",
}
Query:
db.collection.aggregate({$group:{_id: {user_id:"$user_id", site_domain:"$site_domain"}, browser: {$addToSet:{name:"$browser_name", type:"$major"}}, browsing_history: {$addToSet:"$timestamp"}}},
{$group:{_id: {user_id:"$_id.user_id"}, browser:{$addToSet:"$browser"}, sites_visited:{$addToSet:{ site:"$_id.site_domain", times:"$browsing_history"}}}});
Result:
{
"_id" : {
"user_id" : "ab93680ffb1b9c2"
},
"browser" : [
[
{
"name" : "Firefox",
"type" : "20"
}
]
],
"sites_visited" : [
{
"site" : "google.com",
"times" : [
[
"20140201105126",
"1167637060"
]
]
}
]
}
My ideal result for the "browser" key would be:
"browser" : [
{
"name" : "Firefox",
"type" : "20"
}
]
You got most of the way. Just add an $unwind in between. Remember that otherwise you are pushing an array onto another array.
db.collection.aggregate([
{$group:{
_id: {user_id:"$user_id", site_domain:"$site_domain"},
browser: {$addToSet:{name:"$browser_name", type:"$major"}},
browsing_history: {$addToSet:"$timestamp"}
}},
{$unwind: "$browser"}, // de-normalize before next group
{$group:{
_id: {user_id:"$_id.user_id"},
browser:{$addToSet:"$browser"},
sites_visited:
{$addToSet:{ site:"$_id.site_domain", times:"$browsing_history"}}
}}
]);

MongoDB. Find all document where element array have on of the needed element

I have mongodb documents
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Some Name","Another"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another", "Name"],
"zipcode" : ["2224"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000003"),
"name" : ["Yet", "Another", "Name"],
"zipcode" : ["2225"]
}
I need to find elements where "name array" have " Another ", "Name" values.
I tried to use $in, but if there more values, like in
{
"_id" : ObjectId("4e8ae86d08101908e1000003"),
"name" : ["Yet", "Another", "Name"],
"zipcode" : ["2225"]
}
It doesn't return it =(
The use of $in should be fine (as explained below) as long as your data is correct and the values do not contain any whitespace. But if they are not exactly the same you are going to need to do some $regex matching, also using the $and form:
db.collection.find({
$and: [
{name: {$regex: 'Another'} },
{name: {$regex: 'Name'}}
]
})
If you just want to get the one document that has both of, and only the fields values you want, and in the same order just supply the argument as an array:
db.collection.find({ name: ["Another", "Name" ] })
The usage of $in is to match any of the elements you supply as a list. In this case you would match all of your documents
db.collection.find({ name: {$in: [ "Another", "Name" ] } })
For the $all operator, it's function is to match all of elements contained in your argument list, so if an argument was not present in the array being searched it would not be included. So just the last two would match:
db.collection.find({ name: {$all: [ "Another", "Name" ] } })
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another", "Name"],
"zipcode" : ["2224"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000003"),
"name" : ["Yet", "Another", "Name"],
"zipcode" : ["2225"]
}
Finally, if you don't know the order of the elements you are matching, while a little contrived, aggregate gives you a way to get out of jail:
db.collection.aggregate([
// Match using $all to reduce the list
{$match: {name: {$all: ["Name","Another"] }}},
// Keep the original document in the _id
{$project:{
_id: {
_id: "$_id",
name: "$name",
zipcode: "$zipcode"
},
name: 1
}},
// Unwind the "name" array
{$unwind: "$name"},
// Count up the entries per _id
{$group: { _id: "$_id", count: {$sum: 1}}},
// Only match *2* as there were two elements we were expecting
{$match: {count: 2} },
// Project back to the original form
{$project: {
_id:0,
_id: "$_id._id",
name: "$_id.name",
zipcode: "$_id.zipcode"
}}
])
And that's all the forms I can think of.
Have you looked at the MongoDB documentation for $in?
Find it here
You'll need to do this:
find({name: { $in: [ "Another", "Name"] }})

MongoDB: Sort on an array and return the same document multiple times in the cursor

Say I have a collection that has these documents in it:
{sort:[1,2,4,6], fruit:'apple'}
{sort:[3], fruit:'cherry'}
{sort:[5], fruit:'orange'}
And I want to run a query similar to this:
db.collection.find().sort({sort: -1})
But have it return the documents without dedupeing them first like this:
{sort:[1,2,4,6], fruit:'apple'}
{sort:[1,2,4,6], fruit:'apple'}
{sort:[3], fruit:'cherry'}
{sort:[1,2,4,6], fruit:'apple'}
{sort:[5], fruit:'orange'}
{sort:[1,2,4,6], fruit:'apple'}
Instead of this:
{sort:[1,2,4,6], fruit:'apple'}
{sort:[3], fruit:'cherry'}
{sort:[5], fruit:'orange'}
Is there any way to achieve this in the current MongoDB?
You can use the aggregation framework's $unwind operator to unwind an array into multiple documents.
db.fruits.aggregate(
{$unwind: "$sort"},
{$sort: {sort: 1}}
)
The $unwind operation "unwinds" an array on a document by creating multiple documents, one for each value in that array. Then, we just sort on the criteria given. So for the inputs:
> db.fruits.insert({sort:[1,2,4,6], fruit:'apple'})
> db.fruits.insert({sort:[3], fruit:'cherry'})
> db.fruits.insert({sort:[5], fruit:'orange'})
We get the resulting output:
> db.fruits.aggregate({$unwind: "$sort"}, {$sort: {sort: 1}})
{
"result" : [
{
"_id" : ObjectId("51f0592c8a542caf3f07fa66"),
"sort" : 1,
"fruit" : "apple"
},
{
"_id" : ObjectId("51f0592c8a542caf3f07fa66"),
"sort" : 2,
"fruit" : "apple"
},
{
"_id" : ObjectId("51f059358a542caf3f07fa67"),
"sort" : 3,
"fruit" : "cherry"
},
{
"_id" : ObjectId("51f0592c8a542caf3f07fa66"),
"sort" : 4,
"fruit" : "apple"
},
{
"_id" : ObjectId("51f0593b8a542caf3f07fa68"),
"sort" : 5,
"fruit" : "orange"
},
{
"_id" : ObjectId("51f0592c8a542caf3f07fa66"),
"sort" : 6,
"fruit" : "apple"
}
],
"ok" : 1
}
If you need to maintain the original sort array, you can use $project to create a projection of the original document that copies the sort field into an expanded_sort field, which is then unwound, like so:
db.fruits.aggregate(
{$project: {sort: 1, fruit: 1, expanded_sort: "$sort"}},
{$unwind: "$expanded_sort"},
{$sort: {expanded_sort: 1}}
)
This gets you results like so:
"result" : [
{
"_id" : ObjectId("51f0592c8a542caf3f07fa66"),
"sort" : [ 1, 2, 4, 6 ],
"fruit" : "apple",
"expanded_sort" : 1
},