Deno aggregate with mongoDB using $lookup and $project - database

I am trying to connect two tables using aggregate in MongoDB and Deno using this library:
https://deno.land/x/mongo#v0.20.1
According to documentation, this is how we can use it.
// aggregation
const docs = await users.aggregate([
{ $match: { username: "many" } },
{ $group: { _id: "$username", total: { $sum: 1 } } },
]);
But there is no facility or scope to connect two different tables using $lookup and $project
Is there any other way to use lookup and project together in Deno?

This is how aggregation works in Deno and deno_mongo.
var data = Report.aggregate([
{
$lookup: {
from: "users",
localField: "senderId",
foreignField: "_id",
as: "sender",
},
},
{
$lookup: {
from: "users",
localField: "reportedId",
foreignField: "_id",
as: "reported",
},
},
{ $match: { status : 1 } },
{ $sort: { createdAt: 1} },
{ $skip: 10 },
{ $limit: 5 },
]).toArray();

Related

Get number of followers for specific page in Mongodb

let's say I have a collection called pages as
{
_id: "pageid",
name: "Mongodb"
},
{
_id: "pageid2",
name: "Nodejs"
}
and user collection as follows
{
_id : "userid1",
following: ["pageid"],
...
},
{
_id : "userid2",
following: ["pageid", "pageid2"],
...
}
how could I make a query to retrieve the pages information along with the number of users follow each page in mongodb, expected result as follows
[
{
_id: "pageid",
name: "MongoDB",
followers: 2
},
{
_id: "pageid2",
name: "Nodejs",
followers: 1
},
]
You can use $lookup and $size to count total followers,
db.pages.aggregate([
{
$lookup: {
from: "user",
localField: "_id",
foreignField: "following",
as: "followers"
}
},
{
$addFields: {
followers: { $size: "$followers" }
}
}
])
Playground

How to use aggregate $lookup in nested data from mongoDB?

I have collections like this:
// tasks
[
{_id: '123', _user: '345', _solutions: ['567', '678'] }
]
// solutions
[
{ _id: '567', _task: '123', _user: '345' },
{ _id: '678', _task: '123', _user: '345' }
]
// users
[
{ _id: '345', name: 'Tom' }
]
With this code:
await db
.collection<Task>('tasks')
.aggregate([
{ $match: { _id: id } },
{
$lookup: {
from: 'solutions',
// I guess here should be pipeline
localField: '_solutions',
foreignField: '_id',
as: '_solutions',
},
},
{ $lookup: { from: 'users', localField: '_user', foreignField: '_id', as: '_user' } },
])
I have result as below:
task = {
_id: 5e14e877fa42402079e38e44,
_solutions: [
{
_id: 5e15022ccafcb4869c153e61,
_task: 5e14e877fa42402079e38e44,
_user: 5e007403fd4ca4f47df69913, <-- this should be userObject instead
},
{
_id: 5e164f31cafcb4869c153e62,
_task: 5e14e877fa42402079e38e44,
_user: 5e007403fd4ca4f47df69913, <-- this should be userObject instead
}
],
_user: [
{
_id: 5e007403fd4ca4f47df69913,
_solutions: [Array],
_tasks: [Array],
}
]
}
and I don't know how to $lookup into _solutions._user - so instead of objectId I will have exact user object.
You can run $lookup with custom pipeline for outer lookup and the regular one for users:
db.tasks.aggregate([
{
$match: {
_id: "123"
}
},
{
$lookup: {
from: "solutions",
let: { solutions: "$_solutions" },
pipeline: [
{ $match: { $expr: { $in: [ "$_id", "$$solutions" ] } } },
{
$lookup: {
from: "users",
localField: "_user",
foreignField: "_id",
as: "_user"
}
},
{ $unwind: "$_user" }
],
as: "_solutions",
}
}
])
Mongo Playground

Mongo Aggregation with nested array of Id´s

I'm having a Model which is structured similar to this:
{
"_id": ObjectId("5c878c5c18a4ff001b981zh5"),
"books": [
ObjectId("5d963a7544ec1b122ab2ddc"),
ObjectId("5d963be01f663d168f8ea4dc"),
ObjectId("5d963bcb1f663d168f8ea2f4"),
ObjectId("5d963bdf1f663d16858ea7c9"),
}
Now I want to use the aggregation framework to get a list of only the populated books, like:
{ _id: ObjectId("5d963a7544ec1b122ab2ddc"), title: ...., ... },
..
.aggregate([
{
$lookup: {
from: 'books',
let: { books: '$books' },
pipeline: [{ $match: { $expr: { _id: { $in: ['_id', '$$books'] } } } }],
as: 'bookInfos'
}
},
{ $unwind: '$bookInfos' },
{ $replaceRoot: { newRoot: '$bookInfos' } }
])
I am not too sure about your question, but I think this might be what you're looking for.
So this query worked for me:
{
$match: {
_id: user._id,
},
},
{
$lookup: {
from: "books",
localField: "books",
foreignField: "_id",
as: "booksInfo",
},
},
{ $unwind: "$booksInfo" },
{
$replaceRoot: {
newRoot: "$booksInfo",
},
},
Thanks #zishone. Somehow your query returned all the books available in the db and not only the ones from the User Model, but it works as desired when looking up the documents with local and foreignField.

MongoDB Aggregate ObjectId inside Array of embedded Documents

I have seen a ton of question about the $lookup aggregator for arrays of ObjectIds but I can't seem to find anything about when the ObjectId is inside an array of embedded documents.
I have the follow document inside a mongodb database:
_id: ObjectId('...')
Alarms: [
{
Gateway: ObjectId('...')
Port: 1
},
{
Gateway: ObjectId('...')
Port: 2
}
]
I would like to have the following:
_id: ObjectId('...')
Alarms [
{
Gateway: ...(Gateway Object),
Port: 1
},
{
Gateway: ...(Gateway Object),
Port: 2
}
]
I have tried the following with no success:
$lookup: {
from: 'Gateway',
localField: 'Alarms.Gateway',
foreignField: '_id',
as: 'Alarms.Gateway'
}
But this gives me the following result:
_id: ObjectId('...')
Alarms [
{
Gateway: {
...(Gateway Object)
}
Port: 1
}
]
Please try the below queries :
If you don't want the object which doesn't have match in Gateway collection exist in Alarms array in final result :
db.Alarms.aggregate([{ $unwind: '$Alarms' }, {
$lookup: {
from: 'Gateway',
localField: 'Alarms.Gateway',
foreignField: '_id',
as: 'Alarms.Gateway'
}
}, { $match: { 'Alarms.Gateway': { $ne: [] } } },
{ $addFields: { 'Alarms.Gateway': { $arrayElemAt: ['$Alarms.Gateway', 0] } } },
{ $group: { _id: '$_id', Alarms: { $push: '$Alarms' } } }
])
Test : MongoDB-Playground
Otherwise, if you want all objects in Alarms array to be returned irrespective of whether there is a match in Gateway or not :
db.Alarms.aggregate([{ $unwind: '$Alarms' }, {
$lookup: {
from: 'Gateway',
localField: 'Alarms.Gateway',
foreignField: '_id',
as: 'Alarms.GatewayObj'
}
}, { $addFields: { 'Alarms.Gateway': { $cond: [{ $ne: ['$Alarms.GatewayObj', []] }, { $arrayElemAt: ['$Alarms.GatewayObj', 0] }, '$Alarms.Gateway'] } } },
{ $project: { 'Alarms.GatewayObj': 0 } },
{ $group: { _id: '$_id', Alarms: { $push: '$Alarms' } } }
])
Test : MongoDB-Playground
Difference between two queries would be one will return below object in Alarms array (Vs) one don't.
{
"Gateway": ObjectId("5e2b5425d02e05b6940de2fb"),
"Port": 2
}

get sum conditional with mongodb

I need to get the sells sum, just with the idCategory, any idea?
I have this 3 schemas in mongondb
category = [{"id":1,"name":"cat1"}, {"id":2,"name":"cat2"}]
product = [{"id":1,"name":"product1", "catId":1}, {"id":2,"name":"product2", "catId":2}]
sells = [{"id":1,"value":80, "productId":1, status:'active'}, {"id":2,"value":90, "productId":2, status:'Inactive'}]
MongoDB collections are not actual schemas, also, I'm assuming:
You're interpreting them as arrays (although they aren't), so you mean each of your Collections have 2 documents inside of them.
You want the sum of sales grouped by product category.
If those are the cases, what you want is a MongoDB Aggregate which you would run on your "sells" collection, "join" with the "product" collection and group by category id.
The base aggregate to do so would be along the following lines:
sells.aggregate([
{
$lookup: {
from: "product",
localField: "productId",
foreignField: "id",
as: "ProductData"
}
},
{
$unwind: "$ProductData"
},
{
$group: {
_id: "$ProductData.catId",
total: { $sum: "$value" }
}
}
]);
If you also want to fetch the Category name after aggregating, all you need to do is insert another $lookup at the end of the pipeline joining with category collection:
sells.aggregate([
{
$lookup: {
from: "product",
localField: "productId",
foreignField: "id",
as: "ProductData"
}
},
{
$unwind: "$ProductData"
},
{
$group: {
_id: "$ProductData.catId",
total: { $sum: "$value" }
}
},
{
$lookup: {
from: "category",
localField: "_id",
foreignField: "id",
as: "CategoryData"
}
},
{
$unwind: "$CategoryData"
},
{
$project: {
name: "$CategoryData.name",
total: 1
}
}
]);
EDIT (adding new case request on comment):
db.getCollection('product').aggregate([
{
$lookup: {
from: "sells",
localField: "id",
foreignField: "productId",
as: "SalesData"
}
},
{
$unwind:
{
path: "$SalesData",
preserveNullAndEmptyArrays: true
}
},
{
$project: {
catId: 1,
value: "$SalesData.value"
}
},
{
$group: {
_id: "$catId",
total: { $sum: "$value" }
}
},
{
$lookup: {
from: "category",
localField: "_id",
foreignField: "id",
as: "CategoryData"
}
},
{
$unwind: "$CategoryData"
},
{
$project: {
name: "$CategoryData.name",
total: 1
}
}
]);

Resources