MongoDB aggregation lookup array - node.js

I have three documents called location, company and vouchers and they structured as follows,
"company": [
{
"_id": "625ae79a51828244cef979d4",
"name": "C1",
"location": "L1",
"category": "A"
},
{
"_id": "625ba41651828244cefa138b",
"name": "C2",
"location": "L2",
"category": "B"
},
{
"_id": "625ba4d651828244cefa1951",
"name": "C3",
"location": "L3",
"category": "B"
}
]
"vouchers":[
{
"_id":"625ae79a51828244cef979d4",
"name":"V1",
"color":"#ad7f7f",
"category":[
"A",
"B"
]
},
{
"_id":"625ba41651828244cefa138b",
"name":"V2",
"color":"#9A348E",
"category":[
"A"
]
},
{
"_id":"625ba4d651828244cefa1951",
"name":"V3",
"color":"#31263E",
"category":[
"B"
]
},
{
"_id":"625ba4d651828244cefa1951",
"name":"V4",
"color":"#31263E",
"category":[
"C"
]
}
]
and the expected result should be
"companies":[
{
"_id":"625ae79a51828244cef979d4",
"name":"C1",
"location":"L1",
"category":"A",
"vouchers":[
{
"_id":"625ae79a51828244cef979d4",
"name":"V1",
"color":"#ad7f7f",
"category":[
"A",
"B"
]
},
{
"_id":"625ba41651828244cefa138b",
"name":"V2",
"color":"#9A348E",
"category":[
"A"
]
}
]
},
{
"_id":"625ba41651828244cefa138b",
"name":"C2",
"location":"L2",
"category":"B",
"vouchers":[
{
"_id":"625ae79a51828244cef979d4",
"name":"V1",
"color":"#ad7f7f",
"category":[
"A",
"B"
]
},
{
"_id":"625ba4d651828244cefa1951",
"name":"V3",
"color":"#31263E",
"category":[
"B"
]
}
]
},
{
"_id":"625ba4d651828244cefa1951",
"name":"C3",
"location":"L3",
"category":"C",
"vouchers":[
{
"_id":"625ba4d651828244cefa1951",
"name":"V4",
"color":"#31263E",
"category":[
"C"
]
}
]
}
]
I am trying to get the expected result by using mongodb aggregation pipeline. First I filtered location documents with $geoWithin and used $lookup to find the related companies. Next I should get all the vouchers which having same category as company. I applied bellow code to previous result to get vouchers.
$lookup: {
from: "vouchers",
let: { category: "$company.category" },
pipeline: [
{
$match: {
$expr: {
$and: [{ $in: ["$category", "$$category"] }],
},
},
},
],
as: "vouchers",
},
But it gives empty result after this stage. Any suggestion would be appreciated.

Related

Nested update an array of objects in mongodb

I have a problem to writing a mongodb query to nested updating an array of objects.
My current document in the collection is like this:
{
"_id": 1,
"data": {
"arr_1": [
{
"inner_arr_1": [
{
"aid": "111",
"ans": "def"
},
{
"aid": "222",
"ans": "def"
},
],
"inner_arr_2": [
{
"aid": "333",
"ans": "def"
},
{
"aid": "444",
"ans": "def"
},
],
"inner_arr_3": [
{
"aid": "555",
"ans": "def"
},
{
"aid": "666",
"ans": "def"
},
]
},
]
},
"name": "John"
}
I want to write an API endpint by express in nodejs to nested update this document.
The post body of the endpoint is like:
req.body = {
"_id": 1,
"data": {
"arr_1": [
{
"inner_arr_1": [
{
"aid": "111",
"ans": "new val"
}
],
"inner_arr_3": [
{
"aid": "666",
"ans": "new val"
}
]
},
]
}
}
Anyone can help me to write a query to solve this problem?
Thank you.

Mongo Query to get a result

My mongo collection name tests and whose having the following documents in it.
[
{
"title": "One",
"uid": "1",
"_metadata": {
"references": [
{
"uid": "2"
},
{
"asssetuid": 10
}
]
}
},
{
"title": "Two",
"uid": "2",
"_metadata": {
"references": [
{
"uid": "3"
},
{
"asssetuid": 11
}
]
}
},
{
"title": "Three",
"uid": "3",
"_metadata": {
"references": []
}
}
]
And I want the result in the following format (for uid:1)
[
{
"title": "One",
"uid": 1,
"_metadata": {
"references": [
{
"asssetuid": 10
},
{
"asssetuid": 11
},
{
"title": "Two",
"uid": "2",
"_metadata": {
"references": [
{
"title": "Three",
"uid": "3"
}
]
}
}
]
}
}
]
for uid:2 I want the following result
[
{
"title": "Two",
"uid": 2,
"_metadata": {
"references": [
{
"asssetuid": 11
},
{
"title": "Three",
"uid": "3"
}
]
}
}
]
Which query I used here to get a respected result. according to its uid. here I want the result in the parent-child relationship. is this possible using MongoDB graph lookup query or any other query that we can use to get the result. Please help me with this.
New Type Output
[{
"title": "One",
"uid": 1,
"_metadata": {
"assets": [{
"asssetuid": 10,
"parent": 1
}, {
"asssetuid": 11,
"parent": 2
}],
"entries": [{
"title": "Two",
"uid": "2",
"parent": 1
}, {
"title": "Three",
"uid": "3",
"parent": 2
}]
}
}]
Mongo supports the automatic reference resolution using $ref but for that, you need to change your schema a little and resolve resolution is only supported by some drivers.
You need to store your data in this format:
[
...
{
"_id": ObjectId("5a934e000102030405000000"),
"_metadata": {
"references": [
{
"$ref": "collection",
"$id": ObjectId("5a934e000102030405000001"),
"$db": "database"
},
{
"asssetuid": 10
}
]
},
"title": "One",
"uid": "1"
},
....
]
For more details on $ref refer to official documentation: label-document-references
OR
you can resolve the reference using the $graphLookup but the only problem with the $graphlookup is that you will lose the assetuid. Here is the query and it will resolve references and give output in flat map
db.collection.aggregate([
{
$match: {
uid: "1"
}
},
{
$graphLookup: {
from: "collection",
startWith: "$_metadata.references.uid",
connectFromField: "_metadata.references.uid",
connectToField: "uid",
depthField: "depth",
as: "resolved"
}
},
{
"$addFields": {
"references": "$resolved",
"metadata": [
{
"_metadata": "$_metadata"
}
]
}
},
{
"$project": {
"references._metadata": 0,
}
},
{
"$project": {
"references": "$references",
"merged": {
"$concatArrays": [
"$metadata",
"$resolved"
]
}
}
},
{
"$project": {
results: [
{
merged: "$merged"
},
{
references: "$references"
}
]
}
},
{
"$unwind": "$results"
},
{
"$facet": {
"assest": [
{
"$match": {
"results.merged": {
"$exists": true
}
}
},
{
"$unwind": "$results.merged"
},
{
"$unwind": "$results.merged._metadata.references"
},
{
"$match": {
"results.merged._metadata.references.asssetuid": {
"$exists": true
}
}
},
{
"$project": {
_id: 0,
"asssetuid": "$results.merged._metadata.references.asssetuid"
}
}
],
"uid": [
{
"$match": {
"results.references": {
"$exists": true
}
}
},
{
"$unwind": "$results.references"
},
{
$replaceRoot: {
newRoot: "$results.references"
}
}
]
}
},
{
"$project": {
"references": {
"$concatArrays": [
"$assest",
"$uid"
]
}
}
}
])
Here is the link to the playground to test it: Mongo Playground

Query filteration in MongoDB

I have a list of products with the following details:
"products": [{
"product_name": "A",
"product_type": [{
"name": "Metal"
},
{
"name": "Wood"
},
{
"name": "Carbon"
}
],
},
{
"product_name": "B",
"product_type": [{
"name": "Metal"
},
{
"name": "Iron"
}
],
},
{
"product_name": "C",
"product_type": [{
"name": "Metal"
},
{
"name": "Wood"
}
],
},
{
"product_name": "D",
"product_type": [{
"name": "Wood"
}],
}
]
I want to filter this collection with
Product.find(query)
where sending query = ["Wood", "Carbon"] should list me products which has either Wood or Carbon type.
Or works like:
Product.find({product_type: [ { name: query } ]}) list me products with name A, C and D
You can use dot notation with $in to solve your problem:
Product.find({
"product_type.name": {
$in: ["Wood", "Carbon"]
}
})
MongoPlayground
You can write query like,
Product.find({product_name:{$in: [ 'A', 'C', 'D']}}) list me products with name A, C and D
Or if you want to find the documents based on product_type, then you can use following query
Product.find({
"product_type.name": {
$in: [
"Metal"
]
}
})
Refer: https://mongoplayground.net/p/vSfkpUjU494

How can i join 3 collection with aggregation?

Here is my structure
country
[
{
"studentid": [
"5bb482fdac231f1354c47aab"
],
"_id": "5bb672fb92c98117d004c733",
"name": "china",
"__v": 0
}
]
users
[
{
"books": [
"5bb657ea05bf6d0ef096e529",
"5bb6580d05bf6d0ef096e52a"
],
"_id": "5bb482fdac231f1354c47aab",
"firstName": "will",
"lastName": "smith",
"email": "user3#gmail.com",
"address": "rajkot",
"salary": 5000,
"department": "electrical",
"__v": 0
}
]
books
[
{
"_id": "5bb657ea05bf6d0ef096e529",
"name": "book 1",
"price": 100,
"pages": 200,
"__v": 0
}
]
Now i am trying to join this 3 collections each array wise
Here is code that i tried
CountryModel.aggregate([
{ $match: { name: country } },
{
$lookup: {
from: UserModel.collection.name,
let: { student_id: "_id" },
pipeline: [
{ "$match": { "_id": "$student_id" } },
{
$lookup: {
from: UserModel.collection.name,
let: { book_id: "$books" },
pipeline: [
{
$lookup: {
from: BookModel.collection.name,
let: { bookid: "$_id" },
pipeline: [
{ "$match": { "$expr": { "$in": ["$book_id", "$bookid"] } } },
],
as: "more"
}
}
],
as: "books"
}
}
],
as: "studentid"
},
},
])
can someone tell me were i am doing wrong ?

Aggregation with Mongodb using mongoose

Hey im trying some aggregation on mongodb using moongose:
I got this data:
[
{
"school": "1",
"preferences": [
{
"person": "X",
"color": "A"
},
{
"person": "X",
"color": "B"
},
{
"person": "Y",
"color": "A"
}
]
},
{
"school": "2",
"preferences": [
{
"person": "Z",
"color": "A"
},
{
"person": "Y",
"color": "C"
}
]
}
]
I think the data explaisn it self, What i want to get as result is,
when i query for the school that matches '1'. i would like to get this result:
[
{
"_id": "X",
"colors": [
"A",
"B"
]
},
{
"_id": "Y",
"colors": ["A"]
}
]
I used aggregation before, but i cant figure to get this result.
Check this aggregation query :
db.collectionName.aggregate({
"$match": {
"school": "1"
}
}, {
"$unwind": "$preferences"
}, {
"$group": {
"_id": "$preferences.person",
"colors": {
"$addToSet": "$preferences.color" // $addToSet used here only to add distinct color
}
}
})
Edit If you want count the number of color then used group with sum as below :
db.collectionName.aggregate({
"$match": {
"school": "1"
}
}, {
"$unwind": "$preferences"
}, {
"$group": {
"_id": "$preferences.color",
"appears": {
"$sum": 1
}
}
})
EDIT
As per your new requirement you should do following aggregation:
db.collectionName.aggregate({
"$unwind": "$preferences"
},
{
"$group": {
"_id": {
"person": "$preferences.person",
"color": "$preferences.color"
},
"count": {
"$sum": 1
}
}
},
{
"$group": {
"_id": "$_id.person",
"colors": {
"$push": {
"color": "$_id.color",
"count": "$count"
}
}
}
},
{
"$project": {
"_id": 0,
"person": "$_id",
"colors": 1
}
}).pretty()

Resources