I want to check if particular data is present on multiple documents or not.
eg I want to check if email exists in user collection and customer collection if it does then want to fetch the data.
I have tried below query but it fails as it checks only one collection.
db.t_usermasters.aggregate([
{
$match: {
"email" : "test#test.com"
}
},{
$lookup: {
from: "t_customermasters",
localField: "email",
foreignField: "email",
as: "UserDetails"
}
}
]).pretty();
if(db.t_usermasters.count({email: 'test#test.com'})
&& db.t_customermasters.count({email: 'test#test.com'})) {
/* fetch your data here
you can associate these two collections by using a customerId field in your
usermasters collection and then populate it ('customerId')
while fetching the data from usermasters collection */
}
Try this code:
db.t_usermasters.aggregate([
{
$match: {
"email" : "test#test.com"
}
},{
$lookup: {
from: "t_customermasters",
localField: "email",
foreignField: "email",
as: "UserDetails"
}
}, {
$match: {
UserDetails: { $exists: true, $not: {$size: 0} }
}
}
]).pretty();
You need to actually lookup in t_customermasters and project down by conditioning with empty array
db.t_usermasters.aggregate([
{
$match: {
"email" : "test#test.com"
}
},
{
$lookup: {
from: "t_customermasters",
localField:"email",
foreignField:"email",
as: "UserDetails"
}
},
{
$project:{
_id:true,
email:true,
emailExistInBoth:{
$cond:{
if:{
$eq:[{$size:"$UserDetails"},0]
},
then:false,
else:true
}
}
}
},
{
$match:{
"emailExistInBoth":true
}
}
]).pretty();
Related
I try to add field from another collection.
db.CarModifications.aggregate([
{
$lookup: {
from: "CarTypes",
localField: "CarTypeID",
foreignField: "CarTypeID",
as: "carType"
}
},
{
$addFields: {
CarType : "$carType._id"
}
},
{
$unwind: "$CarType"
},
{
$project: {
someField: 0
}
}
]).forEach(function(result) {
db.CarModifications.updateOne({_id: result._id}, {$set: {"CarType": result.CarType}})
})
Aggregation result show correct, but no documents update. What's wrong?
I am using mongoDB as NoSql Database. I have two collections One is CUSTOMER(CID,CNAME) and Other one is SHOP(Bill_No, Type, Amount,CID)
In SHOP Collection, CID is referenced with Customer(CID).Also Type can be either "SELL" or "PURCHASE".
db.CUSTOMER.insertOne({"CID":1,"CNAME":"Mark"});
db.CUSTOMER.insertOne({"CID":2,"CNAME":"Chris"});
db.CUSTOMER.insertOne({"CID":3,"CNAME":"James"});
db.SHOP.insertOne({"Bill_No":1,"TYPE":"SELL","Amount":1000,"CID":1});
db.SHOP.insertOne({"Bill_No":2,"TYPE":"SELL","Amount":350,"CID":2});
db.SHOP.insertOne({"Bill_No":3,"TYPE":"PURCHASE","Amount":450,"CID":1});
db.SHOP.insertOne({"Bill_No":4,"TYPE":"PURCHASE","Amount":360,"CID":3});
db.SHOP.insertOne({"Bill_No":5,"TYPE":"SELL","Amount":800,"CID":3});
What should be query to find the list of customers who has SELL and PURCHASE Both.
So according to given data the output should be like
"CID":1, "NAME":"MARK"
"CID":3, "NAME":"JAMES"
Thanks in advance..
Demo - https://mongoplayground.net/p/ZXylHb2g7Dm
Get all details linked to CUSTOMER from SHOP using $
lookup
Use $group combine all types into 1 document
To match both types "PURCHASE", "SELL" use $all
db.CUSTOMER.aggregate([
{
$lookup: {
from: "SHOP",
let: { c_id: "$CID" },
pipeline: [
{ $match: { $expr: {$eq: [ "$CID", "$$c_id" ] } } },
{ $group: { _id: null, types: { "$addToSet": "$TYPE" } } },
{ $match: { types: { $all: [ "PURCHASE", "SELL" ] } } }
],
as: "trades"
}
},
{ $match: { "trades.types.0": { $exists: true } } },
{ $project: { _id: 0, CID: 1, CNAME: 1 } }
])
You can use $lookup for aggregation, click here for reference.
Syntax
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
In your case the query would be
db.CUSTOMER.aggregate([
{
$lookup:
{
from: "SHOP",
localField: "CID",
foreignField: "CID",
as: "SELL_PURCHASE"
}
}
])
im trying to get only those products for whom no order exists, so each product has an order id, these audit tables were linked to orders, but those orders are now deleted, i need to locate those products with no orders.
I know when doing aggregates if the joining collection has no records its not returning anything as "docs", but how can i get it to return me docs == empty or null only..
db.products.aggregate([
{
$match: {
$and: [
{ "docs": { $exists: false } }
]
}
},
{
$lookup: {
from: "orders",
localField: "orderId",
foreignField: "orderId",
as: "docs"
}
},
{
$unwind:
{
path: "$docs",
preserveNullAndEmptyArrays: true
}
},
{ $limit: 10 }
]).pretty()
db.products.aggregate([
{
$lookup: {
from: "orders",
localField: "orderId",
foreignField: "orderId",
as: "docs"
}
},
{ $match: { docs: [] },
{ $limit: 10 }
]).pretty()
I'm trying an aggregation but I can't find the right pipeline to do it.
So, this is a part of my document model :
//company.js
{
"_id" : "5dg8aa8c435b1e2868c841f6",
"name" : "My Corp",
"externalId" : "d7f348c9-c69b-69c4-923c-91458c53dc22",
"professionals_customers" : [
{
"company" : "6f4d01eb3b948150c2aad9c0"
},
{
"company" : "5dg7aa8c366b1e2868c841f6",
"contact" : "5df8ab5c355b1e2999c841f7"
}
],
}
I try to return the professionnal customers fields hydrated with data, like a classic populate would do.
Company field came from the company collection and contact is provided by the user collection
The desired output must look like :
{
"professionals_customers" : [
{
"company": {
"_id": "6f4d01eb3b948150c2aad9c0",
"name": "Transtar",
"externalId": "d7f386c9-c79b-49c5-905c-90750c42dc22",
},
},
{
"company": {
"_id": "5dg7aa8c366b1e2868c841f6",
"name": "Aperture",
"externalId": "d7f386c9-c69b-49c4-905c-90750c53dc22",
},
"contact" : {
"_id": "5df8ab5c355b1e2999c841f7",
"firstname": "Caroline",
"lastname": "Glados",
"externalId": "d7f386c9-c69b-49c4-905c-90750c53dc22", //same externalId as above, the user belongs to the company
},
}
]
}
At this point I've tried multiple solutions but I can't reach my goal.
let query = [{
$match : { _id : companyId }
},{
$lookup : {
from: 'companies',
localField : 'professionals_customers.company',
foreignField : '_id',
as : 'professionalsCustomers'
}
},{
$lookup : {
from: 'users',
localField : 'professionals_customers.contact',
foreignField : '_id',
as : 'contacts'
}
}]
At this, point I' ve got two new arrays with all the needed informations, but I don't know how to get the right contact grouped with the right company. Also, maybe it's easier to try to populate the data (with $lookup) keeping the initial struct than trying to regroup professionalCustomers and contacts through the shared externalId.
Additional informations :
-An user that belongs to a company has the same externalId.
-I don't want to use a classical populate, after that, I need to do some other operations
Try this query :
db.companies.aggregate([
{ $match: { _id: companyId } },
{ $unwind: "$professionals_customers" },
{
$lookup: {
from: "companies",
localField: "professionals_customers.company",
foreignField: "_id",
as: "professionals_customers.company"
}
},
{
$lookup: {
from: "users",
localField: "professionals_customers.contact",
foreignField: "_id",
as: "professionals_customers.contact"
}
},
{
$addFields: {
"professionals_customers.company": {
$arrayElemAt: ["$professionals_customers.company", 0]
},
"professionals_customers.contact": {
$arrayElemAt: ["$professionals_customers.contact", 0]
}
}
},
{
$group: { _id: "$_id", professionals_customers: { $push: "$professionals_customers" }, data: { $first: "$$ROOT" } }
},
{ $addFields: { "data.professionals_customers": "$professionals_customers" } },
{ $replaceRoot: { newRoot: "$data" } }
])
Test : MongoDB-Playground
Note : If needed you need to convert fields/input which is of type string to ObjectId(). Basic thing is you need to check types of two fields being compared or input-to-field-in-DB matches or not.
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"
}
}
])