how can i aggregate in mongodb? - mongodb

I have two collections points collection and users collection here i want to do aggregation based on userid
points collection
{
"userpoint": "2",
"purchaseid":"dj04944",
"store":"001",
"date":ISODate("2017-11-10T08:15:39.736Z")
"userid"[
objectID("5a7565ug8945rt67"),
objectID("8a35553d3446rt78")
]
},
{
"userpoint": "4",
"purchaseid":"5678sd",
"store":"004",
"date":ISODate("2017-11-11T08:15:39.736Z")
"userid"[
objectID("9a85653d3890rt09")
]
}
users collection
{
objectID("5a7565ug8945rt67"),
"name":"asdf",
"mobinumber":"12345",
},
{
objectID("8a35553d3446rt78"),
"name":"qwr",
"mobinumber":"11111",
},
{
objectID("9a85653d3890rt09"),
"name":"juir",
"mobinumber":"9611",
}
how can i do aggregation
db.points.aggregate([
{
$lookup:
{
from: "users",
localField: "",
foreignField: "",
as: "inventory_docs"
}
}
])
i want to combine both collections
help me out to move forward

If your expected output like bellow
{
"_id" : ObjectId("5a164fa5400096bfa0b3422c"),
"date" : ISODate("2017-11-10T08:15:39.736Z"),
"name" : "asdf",
"mobile" : "12345"
}
The can try this query
db.points.aggregate([
{
$match: {
store: "001",
date: {$lte: ISODate("2017-11-10T08:15:39.736Z"), $gte: ISODate("2017-11-10T08:15:39.736Z")}
}
},
{$unwind: "$userid"},
{
$lookup: {
from: "users",
localField: "userid",
foreignField: "_id",
as: "user"
}
},
{
$project: {
userpoint: 1,
purchaseid: 1,
date: 1,
user: {$arrayElemAt: ["$user", 0]}
}
},
{$match: {"user.name": "asdf"}},
{
$project: {
date: 1,
name: "$user.name",
mobile: "$user.mobinumber"
}
}
])

Related

MongoDB doing $lookup on field of different types yet same content

I know that in logTable the "mailID" is "1234" (String)
and in mailTable the "_id" is 1234 (NumberInt)
But is there any way at all to do this $lookup?
log table
{
"_id" : "mailStuff0234",
"mailID" : "1234",
"typeState" : "NEW",
"changeByType" : "ADMIN"
}
mail table
{
"_id" : NumberInt(1234),
"user" : "torben#sunnythailand.com",
"subject" : "Visit to Atlantis Condo Resort"
}
and here is the aggregate
db.log.aggregate([
{ '$match': { typeState: 'NEW'} },
{ '$lookup': {
from: 'mail',
localField: 'mailID',
foreignField: '_id',
as: 'mail'
} },
{ '$unwind': '$mail' }
], {})
MongoDB 4.0 introduced $toInt operator so you can convert mailID value before applying $lookup.
db.log.aggregate([
{
$addFields: { mailID: { $toInt: "$mailID" } }
},
{
$lookup: {
from: "mail",
localField: "mailID",
foreignField: "_id",
as: "mail"
}
}
])
You can also use $lookup with custom pipeline:
db.log.aggregate([
{
$lookup: {
from: "mail",
let: { mailID: { $toInt: "$mailID" } },
pipeline: [ { $match: { $expr: { $eq: [ "$_id", "$$mailID" ] } } } ],
as: "mail"
}
}
])

Mongodb 3.2 : mongodb aggregation with $project before $lookup

I've a problem, actually I'm trying to join different collections for some operation, but I'm not able to get the result as both "BatchInfo" and "UserInfo" is coming as null.
The reason I'm doing "project" first is because I want to take out "Batch Id" and "User Id" from respective objects and then apply in respective "lookup" "foreignField". Also, I'm using mongo 3.2.
db.getCollection('coursecompletedfeedbacks').aggregate([
{
$project: {
"BATCH" : 1,
"FEEDBACK" : 1,
"USER" : 1,
"batchId" : "$BATCH._id",
"userId" : "$USER._id"
}
},
{
$lookup:{
from: "batches",
localField: "batchId",
foreignField: "_id",
as: "BatchInfo"
}
},
{
$lookup:{
from: "users",
localField: "userId",
foreignField: "_id",
as: "UserInfo"
}
}
])
Try as below:
db.getCollection('coursecompletedfeedbacks').aggregate([
{
$lookup:{
from: "batches",
let: { bId: "$BATCH._id" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$_id", "$$bId"]
}
}
},
],
as: "BatchInfo"
}
},
{
$lookup:{
from: "users",
let: { uId: "$USER._id" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$_id", "$$uId"]
}
}
},
],
as: "UserInfo"
}
},
{
$project: {
"BatchInfo" : 1,
"UserInfo" : 1,
""FEEDBACK" : 1,
}
},
])

Mongodb aggretate apply sort to lookup results, and add field index number

The aggregate was executed.
I got the results using lookup, but I need a sort.
In addition, I want to assign an index to the result value.
CollectionA :
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"contents" : [
ObjectId("AAAAAAAAAAAAAAAAAAAAAAAA"),
ObjectId("BBBBBBBBBBBBBBBBBBBBBBBB")
],
"name" : "jason"
}
CollectionB :
{
"_id" : ObjectId("AAAAAAAAAAAAAAAAAAAAAAAA")
"title" : "a title",
"date" : 2018-01-02
},
{
"_id" : ObjectId("BBBBBBBBBBBBBBBBBBBBBBBB")
"title" : "a title",
"date" : 2018-01-01
}
Query:
db.getCollection('A').aggregate([
{
$match : { "_id" : ObjectId("5a6cf47415621604942386cd") }
},
{
$lookup : {
from: "B",
localField: "contents",
foreignField: "_id",
as: "item"
}
},
{ $sort: { "item.date" : -1 } }
]);
Want Result:
{
"_id" : ObjectId("5a6cf47415621604942386cd"),
"contents" : [
{
"_id" : ObjectId("BBBBBBBBBBBBBBBBBBBBBBBB")
"title" : "a title",
"date" : 2018-01-01,
"index" : 0
},
{
"_id" : ObjectId("AAAAAAAAAAAAAAAAAAAAAAAA")
"title" : "a title",
"date" : 2018-01-02,
"index" : 1
}],
"name" : "jason"
}
The current problem does not apply to the sort.
And I don't know how to designate an index.
Below Aggregation may you. For your desire result.
db.CollectionA.aggregate([
{
$match: { "_id": ObjectId("5a6cf47415621604942386cd") }
},
{
$lookup: {
from: "CollectionB",
let: { contents: "$contents" },
pipeline: [
{
$match: { $expr: { $in: ["$_id", "$$contents"] } }
},
{ $sort: { date: 1 } }
],
as: "contents"
}
},
{
$project: {
contents: {
$map: {
input: { $range: [0, { $size: "$contents" }, 1 ] },
as: "element",
in: {
$mergeObjects: [
{ index: "$$element" },
{ $arrayElemAt: [ "$contents", "$$element" ]}
]
}
}
}
}
}
])
One way to go about it would be to unwind the array, sort it and then group it back
db.A.aggregate([
{
$match: {
"_id": ObjectId("5a6cf47415621604942386cd")
}
},
{
$lookup: {
from: "B",
localField: "contents",
foreignField: "_id",
as: "item"
}
},
{
$unwind: "$item"
},
{
$sort: {
"item.date": -1
}
},
{
$group: {
_id: "$_id",
contents: {
$push: "$item"
}
}
}
])
Another method is, (this is applicable only if the date field corresponds to the document creation date),
db.A.aggregate([
{
$match: {
"_id": ObjectId("5a6cf47415621604942386cd")
}
},
{
$lookup: {
from: "B",
localField: "contents",
foreignField: "_id",
as: "item"
}
},
{
$sort: {
"item": -1
}
}
])
Basically, this sorts on the basis of _id, and since _id is created using the creation date, it should sort accordingly.

Mongodb - $group with $addToSet and then $lookup

I've got the following query
db.getCollection('transportations').aggregate(
{
$group: {
_id: null,
departure_city_id: { $addToSet: "$departure.city_id" },
departure_station_id: { $addToSet: "$departure.station_id" }
}
}
);
and the result is
{
"_id" : null,
"departure_city_id" : [
ObjectId("5a2f5378334c4442ab5a63ea"),
ObjectId("59dae1efe408157cc1585fea"),
ObjectId("5a5bbfdc35628410f9fdcde9")
],
"departure_station_id" : [
ObjectId("5a2f53d1334c4442ab5a63ee"),
ObjectId("5a2f53c5334c4442ab5a63ed"),
ObjectId("5a5bc13435628410f9fdcdea")
]
}
Now i want to lookup each departure_city_id with the collection "areas" to get the "name" of the area and each departure_station_id with the collection "stations" to get also the "name" of the station
The result could be something like this
{
"_id" : null,
"departure_city_id" : [
{
_id: ObjectId("5a2f5378334c4442ab5a63ea"),
name: "City 1
},
{
_id: ObjectId("59dae1efe408157cc1585fea"),
name: "City 2
},
{
_id: ObjectId("5a5bbfdc35628410f9fdcde9"),
name: "City 3
}
],
"departure_station_id" : [
{
_id: ObjectId("5a2f53d1334c4442ab5a63ee"),
name: "Station 1
},
{
_id: ObjectId("5a2f53c5334c4442ab5a63ed"),
name: "Station 2
},
{
_id: ObjectId("5a5bc13435628410f9fdcdea"),
name: "Station 3
}
]
}
The $lookup aggregation pipeline stage NOW works directly with an array (on 3.3.4 version).
See: lookup between local (multiple)array of values and foreign (single) value
The answer of the question is just:
db.getCollection('transportations').aggregate(
{
$group: {
_id: null,
departure_city_id: { $addToSet: "$departure.city_id" },
departure_station_id: { $addToSet: "$departure.station_id" }
}
},
{
$lookup: {
from: "areas",
localField: "departure_city_id",
foreignField: "_id",
as: "departure_city_id"
}
},
{
$lookup: {
from: "stations",
localField: "departure_station_id",
foreignField: "_id",
as: "departure_station_id"
}
}
)

Mongodb aggregation with referred collection

I want to get a list of my second level affiliate users, I've designed the collection like
user
{
"_id" : ObjectId("5a1b9df7bfdbfef2d4f1e9f3"),
"name" : "name 1",
"affKey" : "H1g-CfFxG",
}
{
"_id" : ObjectId("5a1bce5e9a2918f71a9ac4fb"),
"name" : "name 2",
"affKey" : "K1gKJfFxG",
}
affilites
{
"affKey" : "H1g-CfFxG",
"affUsers" : [
ObjectId("5a1bce5e9a2918f71a9ac4fb")
],
}
{
"affKey" : "K1gKJfFxG",
"affUsers" : [
ObjectId("5a1b9e43bfdbfef2d4f1e9f8"),
ObjectId("5a1b9e43bfdbfef2d4f1e911"),
],
}
Here I am saving a new set in affiliate.affKey is based on Users.affKey
Now I want to get a list of my first and second level affiliates, i.e. the list of affiliates of 5a1b9e43bfdbfef2d4f1e9f6 and 5a1bce5e9a2918f71a9ac4fb along with first level affiliate.
expecting the results like
{
first: [first level affiliates] // 1 result
second: [second level affiliates] // 2 results
}
For this situation you have to some steps to get expected result. can follow bellow steps
$lookup the affiliets collection for affKey
Then you have to $lookup the users collection to get the reference user information
After that you have to $lookup again the affiliets collection for second level user affKey
so query can be like bellow
db.users.aggregate([
{
$lookup: {
from: "affilites",
localField: "affKey",
foreignField: "affKey",
as: "affUsers"
}
},
{
$project: {
name: 1,
affKey: 1,
first: {$arrayElemAt: ["$affUsers.affUsers", 0]},
secondLevelUserId: {$arrayElemAt: ["$affUsers.affUsers", 0]}
}
},
{ $unwind: { path: "$secondLevelUserId", "preserveNullAndEmptyArrays": true }},
{
$lookup: {
from: "users",
localField: "secondLevelUserId",
foreignField: "_id",
as: "secondLevelUser"
}
},
{
$project: {
name: 1,
affKey: 1,
first: 1,
secondLevelUser: {$arrayElemAt: ["$secondLevelUser", 0]}
}
},
{
$lookup: {
from: "affilites",
localField: "secondLevelUser.affKey",
foreignField: "affKey",
as: "secondLevelUser"
}
},
{
$project: {
name: 1,
affKey: 1,
first: 1,
second: {$arrayElemAt: ["$secondLevelUser.affUsers", 0]}
}
},
{
$unwind: {
"path": "$second",
"preserveNullAndEmptyArrays": true
}
},
{
$group: {
_id: "$_id",
name: {$first: "$name"},
affKey: {$first: "$affKey"},
first: {$first: "$first"},
second: {$addToSet: "$second"}
}
}
]);
After execute the query you will get result like bellow
first document:
{
"_id" : ObjectId("5a1b9df7bfdbfef2d4f1e9f3"),
"name" : "name 1",
"affKey" : "H1g-CfFxG",
"first" : [
ObjectId("5a1bce5e9a2918f71a9ac4fb")
],
"second" : [
ObjectId("5a1b9e43bfdbfef2d4f1e911"),
ObjectId("5a1b9e43bfdbfef2d4f1e9f8")
]
}
second document
{
"_id" : ObjectId("5a1bce5e9a2918f71a9ac4fb"),
"name" : "name 2",
"affKey" : "K1gKJfFxG",
"first" : [
ObjectId("5a1b9e43bfdbfef2d4f1e9f8"),
ObjectId("5a1b9e43bfdbfef2d4f1e911")
],
"second" : []
}