MongoDB join two collections with between clause - mongodb

There is a collection "Printers":
{
"_id" : ObjectId("5cc02f9b9931de72296ba6c2"),
"model" : "Xerox WorkCentre 3315",
"serial" : "3255498494",
"date" : ISODate("2019-04-25T08:57:48.001+0000"),
"pages" : NumberInt(4868),
"location" : "New location",
"ip" : "10.159.0.35",
"ip_int" : NumberInt(178192419)
}
and "Branches" collection:
{
"_id" : ObjectId("5cb4799b8c0cfe35e4a4c266"),
"name" : "Office 1",
"ip_start" : NumberLong(178192384),
"ip_end" : NumberLong(178194431)
}
// ----------------------------------------------
{
"_id" : ObjectId("5cb479e68c0cfe35e4a4c269"),
"name" : "Office 2",
"ip_start" : NumberLong(3232258048),
"ip_end" : NumberLong(3232258303)
}
"Branches" collection contains ip addresses converted into integer value, i.e. 192.168.0.1 is 3232235521. Each record in Branches describes subnet.
Each printer located in one branch.
If printers.ip_int between branches record [ip_start;ip_end] then query should return all fields from Printer and one field "Name" from "Branches" collection.
How can i do this?

You need a lookup with custom pipeline where you can specify "between" condition:
db.Branches.aggregate([
{
$lookup: {
from: "Printers",
let: { ip_start: "$ip_start", ip_end: "$ip_end" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ "$gte": [ "$ip_int", "$$ip_start" ] },
{ "$lte": [ "$ip_int", "$$ip_end" ] },
]
}
}
}
],
as: "Printers"
}
}
])

db.getCollection("printers").aggregate(
[
{
"$lookup" : {
"from" : "branches",
"let" : {
"ip_int" : "$ip_int"
},
"pipeline" : [
{
"$match" : {
"$expr" : {
"$and" : [{"$gte" : ["$$ip_int", "$ip_start"]},
{ "$lte" : ["$$ip_int", "$ip_end"]}
]
}
}
}
], "as" : "Printers"
}
},
{
"$sort" : {
"ip_int" : 1.0
}
},
{
"$unwind" : {
"path" : "$Printers"
}
},
{
"$addFields" : {
"filial" : "$Printers.name"
}
},
{
"$project" : {
"Printers" : false, "ip_int" : false
}
}
]);

Related

Mongo find query only returns one result

Hello I have the following data structure :
[
{
"name": "a name",
"project": [
{
companyName: "a name",
contactPerson: [
{
work_email: "test#test.com"
}
]
},
{
companyName: "a name1",
contactPerson: [
{
work_email: "test1#test.com"
}
]
},
{
companyName: "a name2",
contactPerson: [
{
work_email: "test2#test.com"
}
]
},
{
companyName: "a name3",
contactPerson: [
{
work_email: "test#test.com"
}
]
},
]
}
]
With this query i want to find all projects that have the email test#test.com :
db.collection.find({
"project.contactPerson.work_email": "test#test.com"
},
{
"project.$": 1
})
It only returns the first result it finds and then it just stops. but in my data i have two projects with that email and i want to find both. here's a playground you can use to further help me if you can. Thanks in advance and much appreciated : https://mongoplayground.net/p/4Mpp7kHi98u
The positional $ operator limits the contents of an to return either:
The first element that matches the query condition on the array.
The first element if no query condition is specified for the array
(Starting in MongoDB 4.4). Ref
You can do something like following,
[
{
"$unwind": "$project"
},
{
$addFields: {
"project.contactPerson": {
$filter: {
input: "$project.contactPerson",
cond: {
$eq: [
"$$this.work_email",
"test#test.com"
]
}
}
}
}
},
{
$match: {
$expr: {
$ne: [
"$project.contactPerson",
[]
]
}
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
project: {
"$addToSet": "$project"
}
}
}
]
Working Mongo playground
db.collection.aggregate([
{
$unwind: "$project"
},
{
$match: {
"project.contactPerson.work_email": "test#test.com"
}
},
{
"$group": {
"_id": "$_id",
"name": {
"$first": "$name"
},
"project": {
"$push": {
"companyName": "$project.companyName",
"contactPersion": "$project.contactPerson"
}
}
}
}
])
//step1(problem statement related find):, find shows all projects even one of the array element of contact is matched, use an aggregate function to display specific email ids
> db.test3.find({ "project.contact.email": "abc2#email.com" }).pretty();
{
"_id" : ObjectId("5f43fdc153e34ac6967fe8ce"),
"name" : "Pega Contractors",
"project" : [
{
"pname" : "pname1",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
},
{
"pname" : "pname2",
"contact" : [
{
"email" : "abc2#email.com"
}
]
},
{
"pname" : "pname3",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
}
]
}
--
//aggregate option:
//Step1: data preparation
> db.test3.find().pretty();
{
"_id" : ObjectId("5f43fdc153e34ac6967fe8ce"),
"name" : "Pega Contractors",
"project" : [
{
"pname" : "pname1",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
},
{
"pname" : "pname2",
"contact" : [
{
"email" : "abc2#email.com"
}
]
},
{
"pname" : "pname3",
"contact" : [
{
"email" : "xyz1#email.com"
}
]
}
]
}
>
//step2: aggregate and unwind project for the next step pipeline input
> db.test3.aggregate([ {$unwind: "$project"}]);
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname1", "contact" : [ { "email" : "xyz1#email.com" } ] } }
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname2", "contact" : [ { "email" : "abc2#email.com" } ] } }
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname3", "contact" : [ { "email" : "xyz1#email.com" } ] } }
//step3: Desired outcome, i.e display data specific to email
> db.test3.aggregate([
... {$unwind: "$project"},
... {$match: {"project.contact.email":"xyz1#email.com"}}
... ]);
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname1", "contact" : [ { "email" : "xyz1#email.com" } ] } }
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname3", "contact" : [ { "email" : "xyz1#email.com" } ] } }
> db.test3.aggregate([ {$unwind: "$project"}, {$match: {"project.contact.email":"acb2#email.com"}} ]);
> db.test3.aggregate([ {$unwind: "$project"}, {$match: {"project.contact.email":"abc2#email.com"}} ]);
{ "_id" : ObjectId("5f43fdc153e34ac6967fe8ce"), "name" : "Pega Contractors", "project" : { "pname" : "pname2", "contact" : [ { "email" : "abc2#email.com" } ] } }
>

MongoDB: Filtering aggregation by field values and nested arrays

I built up a graph structure using MongoDB. I did some complex queries on this structure already, but I am struggling on selecting a subgraph of a given depth starting from a specific node via the aggregation pipeline.
I already did use the $graphLookup to get all the required nodes, which gives the following result:
{ "_id" : "O_4", "name" : "D", "type" : "Info", "links" : [ { "link" : "L_2", "objectId" : "O_1" }, { "link" : "L_4", "objectId" : "O_3" }, { "link" : "L_10", "objectId" : "O_6" } ] }
{ "_id" : "O_2", "name" : "B", "type" : "Info", "links" : [ { "link" : "L_1", "objectId" : "O_1" }, { "link" : "L_3", "objectId" : "O_3" } ] }
{ "_id" : "O_1", "name" : "A", "type" : "Info", "links" : [ { "link" : "L_1", "objectId" : "O_2" }, { "link" : "L_2", "objectId" : "O_4" } ] }
{ "_id" : "O_3", "name" : "C", "type" : "Info", "links" : [ { "link" : "L_3", "objectId" : "O_2" }, { "link" : "L_4", "objectId" : "O_4" }, { "link" : "L_5", "objectId" : "O_5" }, { "link" : "L_6", "objectId" : "O_7" } ] }
{ "_id" : "O_6", "name" : "F", "type" : "System", "links" : [ { "link" : "L_8", "objectId" : "O_7" }, { "link" : "L_9", "objectId" : "O_5" }, { "link" : "L_10", "objectId" : "O_4" } ] }
But now I want to remove the nested "link" objects (in array "links") where the "objectId" is not present in the above result, i.e. in "O_6" the link "L_8" should be removed, since the node "O_7" is not part of the subgraph.
I already tried playing around with $in, $facet and other stuff to get this problem solved, but it seems like I am unable ...
Maybe, you guys can help out?
Edit:
Just found a solution more or less - $filter does a decent job here:
{
$unwind: "$links"
}, {
$group: {
_id: null,
ids: {
$addToSet: "$_id"
},
links: {
$addToSet: "$links"
}
}
}, {
$project: {
links: {
$filter: {
input: "$links",
as: "link",
cond: {
$in: ["$$link.objectId", "$ids"]
}
}
}
}
}, {
$unwind: "$links"
}, {
$replaceRoot: {
newRoot: "$links"
}
}, {
$group: {
_id: "$link"
}
}
Returns what I needed - the list of Link-IDs:
{ "_id" : "L_1" }
{ "_id" : "L_10" }
{ "_id" : "L_3" }
{ "_id" : "L_2" }
{ "_id" : "L_4" }

How to write mongo query

How I can get the total number of seats available for a particular movie (seats present in all the theatres for that movie) from the mongodb schema below.
I need to write a mongo query to get the results
{
"_id" : ObjectId("5d637b5ce27c7d60e5c42ae7"),
"name" : "Bangalore",
"movies" : [
{
"name" : "KGF",
"theatres" : [
{
"name" : "PVR",
"seats" : 45
},
{
"name" : "IMAX",
"seats" : 46
}
]
},
{
"name" : "Avengers",
"theatres" : [
{
"name" : "IMAX",
"seats" : 50
}
]
}
],
"_class" : "com.BMS_mongo.ZZ_BMS_mongo_demo.Entity.CityInfo"
}
I have written this code :
db.cities.aggregate( [
{ "$unwind" : "$movies" }, { "$unwind" : "$theatres" } ,
{ "$group" : { _id : "$movies.theatre`enter code here`s.seats" ,
total : { "$sum" : "$seats" } }
}
] )
My schema:
The following query can get us the expected output:
db.collection.aggregate([
{
$unwind:"$movies"
},
{
$unwind:"$movies.theatres"
},
{
$group:{
"_id":"$movies.name",
"movie":{
$first:"$movies.name"
},
"totalSeats":{
$sum:"$movies.theatres.seats"
}
}
},
{
$project:{
"_id":0
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d637b5ce27c7d60e5c42ae7"),
"name" : "Bangalore",
"movies" : [
{
"name" : "KGF",
"theatres" : [
{
"name" : "PVR",
"seats" : 45
},
{
"name" : "IMAX",
"seats" : 46
}
]
},
{
"name" : "Avengers",
"theatres" : [
{
"name" : "IMAX",
"seats" : 50
}
]
}
],
"_class" : "com.BMS_mongo.ZZ_BMS_mongo_demo.Entity.CityInfo"
}
Output:
{ "movie" : "Avengers", "totalSeats" : 50 }
{ "movie" : "KGF", "totalSeats" : 91 }
Query:
db.movie.aggregate([{ $unwind: { path: "$movies",} },
{ $unwind: { path: "$movies.theatres",} },
{ $group: { _id: "$movies.name", "moviename": { $first: "$movies.name" },
"totalSeats": { $sum: "$movies.theatres.seats" }} }])
I got the answer using this query ...
db.cities.aggregate( [
{ "$match" : { "name" : "Bangalore" } },
{ "$unwind" : "$movies" } ,
{ "$match" : {"movies.name" : "KGF"} },
{ "$unwind" : "$theatres" },
{ "$group" : { _id : "$movies.name", total : { "$sum" : "$movies.theatres.seats"
} } }
] )

Group by array element in Mongodb

We have nested document and trying to group by array element. Our document structure looks like
/* 1 */
{
"_id" : ObjectId("5a690a4287e0e50010af1432"),
"slug" : [
"true-crime-the-10-most-infamous-american-murder-mysteries",
"10-most-infamous-american-murder-mysteries"
],
"tags" : [
{
"id" : "59244aa6b1be5055278e9b5b",
"name" : "true crime",
"_id" : "59244aa6b1be5055278e9b5b"
},
{
"id" : "5924524db1be5055278ebd6e",
"name" : "Occult Museum",
"_id" : "5924524db1be5055278ebd6e"
},
{
"id" : "5a690f0fc1a72100110c2656",
"_id" : "5a690f0fc1a72100110c2656",
"name" : "murder mysteries"
},
{
"id" : "59244d71b1be5055278ea654",
"name" : "unsolved murders",
"_id" : "59244d71b1be5055278ea654"
}
]
}
We want to find list of all slugs group by tag name. I am trying with following and it gets result but it isn't accurate. We have hundreds of records with each tag but i only get few with my query. I am not sure what i am doing wrong here.
Thanks in advance.
// Requires official MongoShell 3.6+
db.getCollection("test").aggregate(
[
{
"$match" : {
"item_type" : "Post",
"site_id" : NumberLong(2),
"status" : NumberLong(1)
}
},
{$unwind: "$tags" },
{
"$group" : {
"_id" : {
"tags᎐name" : "$tags.name",
"slug" : "$slug"
}
}
},
{
"$project" : {
"tags.name" : "$_id.tags᎐name",
"slug" : "$_id.slug",
"_id" : NumberInt(0)
}
}
],
{
"allowDiskUse" : true
}
);
Expected output is
TagName Slug
----------
true crime "true-crime-the-10-most-infamous-american-murder-mysteries",
"10-most-infamous-american-murder-mysteries"
"All records where tags true crime"
Instead of using slug as a part of _id you should use $push or $addToSet to accumulate them, try:
db.test.aggregate([
{
$unwind: "$tags"
},
{
$unwind: "$slug"
},
{
$group: {
_id: "$tags.name",
slugs: { $addToSet: "$slug" }
}
},
{
$project: {
_id: 1,
slugs: {
$reduce: {
input: "$slugs",
initialValue: "",
in: {
$concat: [ "$$value", ",", "$$this" ]
}
}
}
}
}
])
EDIT: to get comma separated string for slugs you can use $reduce with $concat
Output:
{ "_id" : "murder mysteries", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "Occult Museum", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "unsolved murders", "slugs" : ",10-most-infamous-american-murder-mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }
{ "_id" : "true crime", "slugs" : ",10-most-infamous-american-murder- mysteries,true-crime-the-10-most-infamous-american-murder-mysteries" }

How to return all matched embedded array documents excluding all other field in array meteor mongo

I have following collection. "addedDetails" is a embedded array document. i want to match HM project and retrieve corresponding value in kk dash board
{
"_id" : "eJHHpB4DkBfLh9kQH",
"dashBoardName" : "kk",
"addedDetails" : [
{
"jid" : "reZYYfWxP9Da9FdZP",
"job" : "job1",
"project" : "HM",
"buildStatus" : "FAILURE"
},
{
"jid" : "KvBcagCuB9DtZa9Wm",
"job" : "job 2",
"project" : "HM",
"buildStatus" : "SUCCESS"
},
{
"jid" : "raiTB4mQ5TmE2d2Jn",
"job" : "job3",
"project" : "CEI",
"buildStatus" : "FAILURE"
},
{
"jid" : "rEmuq6Shtz2vW6Pf3",
"job" : "job4",
"project" : "RI",
"buildStatus" : "FAILURE"
}
]
}
{
"_id" : "muzA3wjGYfk9Ye5pE",
"dashBoardName" : "ss",
"addedDetails" : [
{
"jid" : "MkTsPB5xgkZKGShSq",
"job" : "job1",
"project" : "HM",
"buildStatus" : "SUCCESS"
}
]
}
Expected retun value:
{
"_id" : "eJHHpB4DkBfLh9kQH",
"dashBoardName" : "kk",
"addedDetails" : [
{
"jid" : "reZYYfWxP9Da9FdZP",
"job" : "job1",
"project" : "HM",
"buildStatus" : "FAILURE"
},
{
"jid" : "KvBcagCuB9DtZa9Wm",
"job" : "job2",
"project" : "HM",
"buildStatus" : "SUCCESS"
}
]}
}
my query:
'listjobName': function(){
return dashBoard.find({"dashBoardName":"kk","addedDetails.project":"HM"},{addedDetails: { $all: [{ "$elemMatch" : { project: "HM" }}]}} );
}
Please some one help me to correct the query. here all the value in dash board kk is returned.
db.collection.aggregate(
// Pipeline
[
// Stage 1
{
$match: {
"dashBoardName": "kk"
}
},
// Stage 2
{
$unwind: {
path: '$addedDetails'
}
},
// Stage 3
{
$match: {
'addedDetails.project': 'HM'
}
},
// Stage 4
{
$group: {
_id: {
_id: '$_id',
dashboardName: '$dashBoardName'
},
addedDetails: {
$addToSet: '$addedDetails'
}
}
},
// Stage 5
{
$project: {
dashBoardName: '$_id.dashboardName',
_id: '$_id._id',
addedDetails: 1
}
},
]
);
db.collection_name.aggregate( [
{ $unwind : "$addedDetails" },
{ $match :
{
$and: [ { "dashBoardName" : "kk" }, { "addedDetails.project" : "HM" } ]
}
},
{ $group :
{ _id : " $_id",
dashBoardName : { $first : "$dashBoardName"},
addedDetails : { $push : "$addedDetails" }
}
}
])
Outputs:
{
"_id" : "eJHHpB4DkBfLh9kQH",
"dashBoardName" : "kk",
"addedDetails" : [
{
"jid" : "reZYYfWxP9Da9FdZP",
"job" : "job1",
"project" : "HM",
"buildStatus" : "FAILURE"
},
{
"jid" : "KvBcagCuB9DtZa9Wm",
"job" : "job 2",
"project" : "HM",
"buildStatus" : "SUCCESS"
}
]
}