I have following collections:
Collection A
{
"_id" : ObjectId("5aaa3b170e26ed1eba223ba9"),
"name" : "A1",
"ref" : {
"$ref" : "B",
"$id" : ObjectId("5aaa33740e26ed1eba223ba1")
}
}
{
"_id" : ObjectId("5aaa3b170e26ed1eba223baa"),
"name" : "A2",
"ref" : {
"$ref" : "C",
"$id" : ObjectId("5aaa33740e26ed1eba223ba2")
}
}
Collection B
{
"_id" : ObjectId("5aaa33740e26ed1eba223ba1"),
"name" : "B1"
}
...
Collection C
{
"_id" : ObjectId("5aaa33740e26ed1eba223ba2"),
"name" : "C1"
}
...
It is posable to get folowing result?
{
"_id" : ObjectId("5aaa3b170e26ed1eba223ba9"),
"name" : "A1",
"result" : [
{
"name" : "B1"
}
]
}
{
"_id" : ObjectId("5aaa3b170e26ed1eba223baa"),
"name" : "A2",
"result" : [
{
"name" : "C1"
}
]
}
I tried it with $Project and §Lookups, unfortunately withou success.
Hire is example:
db.A.aggregate([
{$project: {
name : 1,
refId: {$arrayElemAt: [{$objectToArray:"$ref"},1]},
refCol: {$arrayElemAt: [{$objectToArray:"$ref"},0]},
}
},
{$lookup : {
from : "refCol.v",
localField : "refId.v",
foreignField : "_id",
as : "result"
}
},
{$project : {"result._id" : 0, refId : 0, refCol : 0}}
])
In this example I can't reference the "refCol.v" field in the $lookup function.
Have someone a tip or a better solution for me?
You can achieve this by populate() method:
const collectionA = require('../models/collectionA');
collectionA.find({}).populate({
path: 'collectionB',
select: {
'name': 1,
'_id': 0
}
})
}).then((data) => {
if (data) {
res.send(data);
}
}).catch((err) => {
res.send(err);
})
Related
I have two collections user and post
> db.user.find().pretty()
{
"_id" : ObjectId("5d1473bc1b48d9309580a9de"),
"user_id" : NumberLong(1),
"region" : "US",
"is_join" : true
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9df"),
"user_id" : NumberLong(2),
"region" : "KR",
"is_join" : true
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e0"),
"user_id" : NumberLong(3),
"region" : "US",
"is_join" : true
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e1"),
"user_id" : NumberLong(4),
"region" : "US",
"is_join" : true
}
{
"_id" : ObjectId("5d1487fc1b48d9321ff5dc1f"),
"user_id" : NumberLong(5),
"region" : "US",
"is_join" : true
}
> db.post.find().pretty()
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e2"),
"post_id" : NumberLong(1),
"user_id" : NumberLong(3),
"body" : "hi"
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e3"),
"post_id" : NumberLong(2),
"user_id" : NumberLong(1),
"body" : "hello"
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e4"),
"post_id" : NumberLong(3),
"user_id" : NumberLong(2),
"body" : "go"
}
{
"_id" : ObjectId("5d1473bc1b48d9309580a9e5"),
"post_id" : NumberLong(4),
"user_id" : NumberLong(4),
"body" : "python"
}
{
"_id" : ObjectId("5d14941b1b48d93314907345"),
"post_id" : NumberLong(5),
"user_id" : NumberLong(1),
"body" : "aa"
}
I want to join via mongo aggregate lookup operation.
So I made query like this.
db.user.aggregate([
{
'$match': {
'region': 'US',
}
},
{
'$lookup': {
'from': 'post',
'localField': 'user_id',
'foreignField': 'user_id',
'as': 'user'
}
},
{
'$project': {
'_id': 0,
'user.post_id': 1
}
}
])
Result
{ "user" : [ { "post_id" : NumberLong(2) }, { "post_id" : NumberLong(5) } ] }
{ "user" : [ { "post_id" : NumberLong(1) } ] }
{ "user" : [ { "post_id" : NumberLong(4) } ] }
{ "user" : [ ] }
As you know that post_id is unordered.
But I want to sort it descending.
Desired result
{ "user" : [ { "post_id" : NumberLong(1) } ] }
{ "user" : [ { "post_id" : NumberLong(2) } ] }
{ "user" : [ { "post_id" : NumberLong(4) } ] }
{ "user" : [ { "post_id" : NumberLong(5) } ] }
Even Better
{ "user" : [ 1, 2, 4, 5 }] }
How can I modify aggregate query?
Thanks.
You can do following to get what you want:
1) $unwind the user array
2) use $sort to sort all documents with post_id
3) use $group as the next stage in your aggregation query, and push user.post_id to form one sorted user array from all the docs:
db.user.aggregate([
{
'$match': {
'region': 'US',
}
},
{
'$lookup': {
'from': 'post',
'localField': 'user_id',
'foreignField': 'user_id',
'as': 'user'
}
},
{
$unwind : {
path : "$user",
preserveNullAndEmptyArrays : true
}
},
{
$sort : {
'user.post_id' : 1
}
},
{
$group : {
_id : null,
user : {
$push : "$user.post_id"
}
}
}
])
Read more about $sort , $unwind and $group for more information.
I have a MongoDB collection that is looking like this:
{
players: [
{uuid: "A"},
{uuid: "B"}
]
},
{
players: [
{uuid: "A"},
{uuid: "C"}
]
},
{
players: [
{uuid: "D"},
{uuid: "E"}
]
}
I want to use results of a previous aggregation stage and now find all documents where a player shows up, using a $lookup stage:
from: "collection",
pipeline: [
{
$match: {
players: {
$elemMatch: {
uuid: "$playerId"
}
}
//using "players.uuid": "$playerId" doesn't work either
}
}
],
as: "field"
The input to my $lookup stage looks like this:
{
"playerId" : "A"
}
{
"playerId" : "B"
}
{
"playerId" : "C"
}
This query returns an empty array in field. It seems like $uuid is not getting evaluated correctly, because if I exchange $uuid with a hardcoded value (e.g. A), this query returns results.
I have also tried using the let property, this gave me the same result.
What am I doing wrong?
Using the documents you've provided. I believe this might work for you:
I've used $lookup to do a join onto the collection which holds the playerId, which creates an array called field. I then use $unwind to extract all the array elements from both field and player. Finally I use $cond to crosscheck if both values match.
db.getCollection('foo').aggregate([
{ $lookup : {
from: "bar",
localField: "players.uuid",
foreignField: "playerId",
as: "field"
} },
{ $unwind : "$players" },
{ $unwind : "$field" },
{ $project : {
"players": 1,
"field" : 1,
"isMatch": {
"$cond": [ { "$eq": ["$players.uuid", "$field.playerId"] }, 1, 0 ]
} } }
])
I've purposely left the output verbose..
/* 1 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 1.0
}
/* 2 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f539b337e8d2b97ff2fff"),
"playerId" : "B"
},
"isMatch" : 0.0
}
/* 3 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "B"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 0.0
}
/* 4 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "B"
},
"field" : {
"_id" : ObjectId("5a7f539b337e8d2b97ff2fff"),
"playerId" : "B"
},
"isMatch" : 1.0
}
/* 5 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 1.0
}
/* 6 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f53a8337e8d2b97ff3000"),
"playerId" : "C"
},
"isMatch" : 0.0
}
/* 7 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "C"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 0.0
}
/* 8 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "C"
},
"field" : {
"_id" : ObjectId("5a7f53a8337e8d2b97ff3000"),
"playerId" : "C"
},
"isMatch" : 1.0
}
Given this dataset and this mongodb, how to properly convert this aggregation into Mongoose?
I have included, the code using mongoose, which works but I want to know if this is the right way of doing it and that if this aggregation can be improved?
Thanks.
db.cars.aggregate(
//De-normalized the nested array of accounts
{"$unwind": "$accounts"},
//De-normalized the nested array of cars
{"$unwind": "$accounts.cars"},
//match carId to 3C
{"$match": {"accounts.cars.carId" : "3C"}},
//Project the accounts.cars object only
{"$project" : {"accounts.cars" : 1}}
).pretty();
The Mongoose version that I'm trying to improve:
Car.aggregate()
.unwind('accounts')
.unwind('accounts.cars')
.match({'accounts.cars.carId' : "3C"})
.project({"accounts.cars": 1, _id: 0})
.exec(function (err, carsObj) {});
and the dataset (cars):
{
"_id" : ObjectId("56223329b64f07a40ef1c15c"),
"username" : "john",
"email" : "john#john.com",
"accounts" : [
{
"_id" : ObjectId("56322329b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "6A",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
},
{
"carId" : "6B",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
}
]
}
]
},
{
"_id" : ObjectId("56223125b64f07a40ef1c15c"),
"username" : "paul",
"email" : "paul#paul.com",
"accounts" : [
{
"_id" : ObjectId("5154729b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "5B",
"_id" : ObjectId("56323329854f07a40ef1c15e")
}
]
},
{
"_id" : ObjectId("56322117b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "6G",
"_id" : ObjectId("51212929b64f07a40ef1c15e")
},
{
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
},
{
"carId" : "4N",
"_id" : ObjectId("51241279b64f07a40ef1c15e")
}
]
}
]
}
What the aggregation returns is:
[
{ accounts:
{ cars:
{
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
}
}
}
]
I have this collection...
> db.banks.find().pretty()
{
"_id" : ObjectId("54f37cbb44aec3b01b7db8f4"),
"name" : "A",
"branches" : [
{
"branch_id" : 8561,
"name" : "X",
},
{
"branch_id" : 8576,
"name" : "Y",
}
]
}
{
"_id" : ObjectId("54f37cbb44aec3b01b7db8f5"),
"name" : "B",
"branches" : [
{
"branch_id" : 3238,
"name" : "Z",
}
]
}
with this command :
db.banks.aggregate({$project{"branches.name":1,"_id":0}});
get this result :
{ "branches" : { { "name" : "X" }, { "name" : "Y" } } }
{ "branches" : { { "name" : "Z" } } }
but; how I get this result?
(In fact, one object and without "branches".)
{{"name" : "X"}, {"name" : "Y"}, {"name" : "Z"}}
very thanks...
One way you could go about this is to do an $unwind first in the aggregation pipeline to get a deconstructed array with a document for each element and then group by the array element $branches.name:
db.banks.aggregate([
{ $unwind: '$branches'},
{
$group: {
_id: {
name: '$branches.name'
}
}
},
{
$project: {
_id: 0,
name: '$_id.name'
}
},
{ $sort : { "name" : 1 } }
])
Outputs:
{
"result" : [
{
"name" : "X"
},
{
"name" : "Y"
},
{
"name" : "Z"
}
],
"ok" : 1
}
I have a collection which has a field of array kind. I want to sort on the basis of a field of sub-array but Mongo is not sorting the data.
My collection is:
{
"_id" : ObjectId("51f1fcc08188d3117c6da351"),
"cust_id" : "abc123",
"ord_date" : ISODate("2012-10-03T18:30:00Z"),
"status" : "A",
"price" : 25,
"items" : [{
"sku" : "ggg",
"qty" : 7,
"price" : 2.5
}, {
"sku" : "ppp",
"qty" : 5,
"price" : 2.5
}]
}
My Query is:
db.orders.aggregate([
{ "$unwind" : "$items"} ,
{ "$match" : { }} ,
{ "$group" : { "items" : { "$addToSet" : { "sku" : "$items.sku"}} , "_id" : { }}} ,
{ "$sort" : { "items.sku" : 1}} ,
{ "$project" : { "_id" : 0 , "items" : 1}}
])
Result is:
"result" : [
{
"items" : [
{
"sku" : "ppp"
},
{
"sku" : "ggg"
}
]
}
],
"ok" : 1
}
Whereas "sku":"ggg" should come first when it is ascending.
You weant to do the sort BEFORE you regroup:
db.orders.aggregate([
{ "$unwind" : "$items"} ,
{ "$sort" : { "items.sku" : 1}},
{ "$match" : { }} ,
{ "$group" : { "items" : { "$push" : { "sku" : "$items.sku"}} , "_id" : null}} ,
{ "$project" : { "_id" : 0 , "items" : 1}}
])