0

below is all the description collection 1 : users

"_id" : ObjectId("5e2977e1cc1208c65c00648b"),
        "mappedShops" : [
                ObjectId("5e2976cbcc1208c65c006488"),
                ObjectId("5e2976cbcc1208c65c00690c"),
                ObjectId("5e2976cbcc1208c65c006499")
       "phoneNo" : 6789012345,
        "name" : "acdbcs",
        "address" : "address 2",
        "shopCode" : "D3137",
        "state" : "M.P",
        "city" : "Indore"

NOTE: deatils of mappedShops for e.g: ObjectId("5e2976cbcc1208c65c00690c") is in the same users collection
collection 2 : orders

"_id" : ObjectId("5e27f998a42d441fe8a8957f"),
        "isApproved" : false,
"orderCreatedOn" : ISODate("2020-01-22T18:30:00Z"),
"shopOrder" : [],
"frequency" : "WE",
"orderCreatedBy" : ObjectId("5e2976cbcc1208c65c00690c")

Collection 3: payments

 "_id" :  ObjectId("5dd7900bcd00d33c245abbfa"),
 "paymentOfTheDay" : 400,
 "outstanding" : 100,
 "paymentDoneBy":ObjectId("5e2976cbcc1208c65c00690c")

scenario is : i will get _id(i.e admin id) from req.body Here is what i need to do 1: i need to know all the mappedShops objectId's & than for all those objectId's i need to find the details of all those objectId's 2: than i need to look what order that shop has created from order collection.(for all those id's) 3: than i need to look what is the outstanding from the payments collection(again for all the id's) Here is what i need to send to the frontend in the mentioned object Array {"name","phoneNo","address"}(from users collection)+{"orderCreatedOn": ISODate("2020-01-22T18:30:00Z"),"isApproved"}(from orders collection)+{"outstanding"}(from payments collection) expected response may look like this:

"shopsListDetails":[{
"phoneNo","name","address","shopCode" ,"isApproved","outstanding"
}]

POSTMAN REQUEST this is the id of admin

{
    "_id": "5e2977e1cc1208c65c00648b"
}

ultimately front end shall receive all the data which i mentioned in shopsListDetails[{}] for all the mappedShops in the user collection against that admin I am kind of very much stuck in this if any can help me out

2 Answers2

0

Considering the first schema you shared is of User

I am assuming You are storing order_id inside payments Schemama

You can write aggregate query like this

    User.aggregate([
        {
            $match:{
                _id:req.body.admin_id
            }
        },{
            $unwind:'$mappedShops'
        },{
            $lookup:{
                from:'users',
                localField:'mappedShops',
                foreignField:'_',
                as:'mappedShops'
            }
        },{
            $unwind:'$mappedShops'
        },{
            $lookup:{
                from:'orders',
                localField:'mappedShops._id',
                foreignField:'orderCreatedBy',
                as:'order'
            }
        },{
            $unwind:'$order'
        },{
            $lookup:{
                from:'payments',
                localField:'order._id',
                foreignField:'order_id',
                as:'payment'
            }
        },{
            $unwind:'$payment'
        },{
            $project:{
                _id:0,
                name:'$mappedShops.name',
                phoneNo:'$mappedShops.phoneNo',
                address:'$mappedShops.address',
                orderCreatedOn:'$order.orderCreatedOn',
                isApproved:'$order.isApproved',
                outstanding:'$payment.outstanding'
            }
        }
    ])
  1. Firstly, we unwind all the mappedShops & get individual objects of the same from Lookups | This gives us the User details for final data
  2. Then, we find matching order for each mappedshops from orders collection by $lookup & $unwind same | This gives us the order details for final data
  3. Lastly, We match order_id inside payments collection through $lookup & get payment status of each order | This gives us the payment status for final data

PS : For this to worker, you must have the entry of each order in both orders & payments collection, whether or not payment is completed

Comment below if you need more clarification / any change is needed here

Sarfraaz
  • 1,273
  • 4
  • 15
  • no there is no order_id in payments collection but there is shop_id in payments collection can that be used in this case @Sarfraaz – sachin.pandey Jan 28 '20 at 06:19
  • Not a very god practice, You need to store id of particular `order` inside payment collection, because there will be multiple `orders` from same `shop_id`, so you can't know which `payment` is for which `order` – Sarfraaz Jan 28 '20 at 06:21
  • you are absolutely right but actually a bit of background orders wud be created againt shopid's at midnight (chron job) shop can login after 6am and they will be able to edit the orders actually so each shop wud have onle one order id for that particular date, that was the reason in payment collection we have shopid u can understand business requirements :-) cant do much abt it @Sarfraaz – sachin.pandey Jan 28 '20 at 06:29
  • In that case, You'd need to have date stored in both order & payment collection, so we can match that to find payment of particular order, not the best solution, but that would work in your case – Sarfraaz Jan 28 '20 at 06:37
  • okay let me try that and can i also use "orderCreatedBy" from orders collection and "paymentDoneBy" from payments collections – sachin.pandey Jan 28 '20 at 06:40
  • no, that would be possible only if you have exactly one order & exactly one payment from each user – Sarfraaz Jan 28 '20 at 06:42
  • 1
    okay let me try that out please do reply in case i need more clarification on this – sachin.pandey Jan 28 '20 at 06:48
  • Yeah, sure. I am here to help – Sarfraaz Jan 28 '20 at 06:49
  • can you have a look into this and help me out what might be wrong https://stackoverflow.com/questions/59962164/query-working-in-mongoshell-but-not-in-nodejs – sachin.pandey Jan 29 '20 at 08:50
0

Please try this :

db.users.aggregate([
    {
        $match: {
            _id: req.body.adminID
        }
    }, {
        $lookup: {
            from: 'users',
            localField: 'mappedShops',
            foreignField: '_id',
            as: 'mappedShops'
        }
    }, { $unwind: '$mappedShops'}, { $replaceRoot: { newRoot: "$mappedShops" } },
    { 
       $lookup:
        {
            from: "orders",
            let: { mappedShopsId: "$_id" },
            pipeline: [
                {
                    $match: { $expr: { $eq: ["$orderCreatedBy", "$$mappedShopsId"] } }
                },
                { $project: { orderCreatedOn: 1, isApproved: 1 } }
            ],
            as: "orders"
        }
    },{
       $lookup:
        {
            from: "payments",
            let: { mappedShopsId: "$_id" },
            pipeline: [
                {
                    $match: { $expr: { $eq: ["$paymentDoneBy", "$$mappedShopsId"] } }
                },
                { $project: { outstanding: 1 } }
            ],
            as: "payments"
        }
    },
    { $project: { name: 1, phoneNo: 1, address: 1, shopCode: 1, orders: 1, payments: 1 } }
])

Test : MongoDB-Playground

whoami - fakeFaceTrueSoul
  • 17,086
  • 6
  • 32
  • 46
  • db.users.aggregate([ { $match: { _id: ObjectId("5e2977e1cc1208c65c00648b") } }, { $lookup: { from: 'users', localField: 'mappedShops', foreignField: '_id', as: 'mappedShops'........ this one foreignField: '_id', represents the "_id" field of the users collection itself right? @ srinivasy – sachin.pandey Jan 28 '20 at 06:37
  • @sachin.pandey : Yes correct, try that query & let me know !! In first $match replace _id: ObjectId("5e2977e1cc1208c65c00648b") with _id:req.body.adminID, In result I've left orders & payments as arrays cause if your mappedShops might have multiple matching(which is usual) in orders & payments then it would be easy as arrays to differentiate between & best to denote !! – whoami - fakeFaceTrueSoul Jan 28 '20 at 06:54
  • yes your query is working in shell but not in nodejs my code in nodejs is almost same as your query except exports.vendorWiseIndent = async (req, res, next) => { const { adminId } = req.body try { const shopsListDetails= await User.aggregate([{ $match: { _id: adminId } }..."rest is your query exaclty same than"....return res.status(200).json({ shopsListDetails }); } catch (error) { res.send(error); } } POSTMAN RESPONSE: { "shopsListDetails": [] }@ srinivasy – sachin.pandey Jan 28 '20 at 07:30
  • @sachin.pandey : that's because your `adminId` from request is string (Vs) in mongo document it is `ObjectId()`, So you need to convert by doing `var mongoose = require('mongoose'); var id = mongoose.Types.ObjectId('adminId');` -> finally pass `id` as input in query. Check this :: https://stackoverflow.com/questions/6578178/node-js-mongoose-js-string-to-objectid-function – whoami - fakeFaceTrueSoul Jan 28 '20 at 07:32
  • yes but i tried that after converting _id: mongoose.Types.ObjectId(adminId) still getting an empty array – sachin.pandey Jan 28 '20 at 07:48
  • @sachin.pandey : If it is working in shell it has to work with nodejs, just try ‘.find()’ on same adminId and check if proper doc is being returned, also throughout query check field names nd field types match with actual docs( though this is not required if query works in shell), first print adminId from request and check it.. – whoami - fakeFaceTrueSoul Jan 28 '20 at 07:51
  • @sachin.pandey : Also your code has ‘next’ so again u r using ‘await’ check if your response is actually waiting until db call is done.. – whoami - fakeFaceTrueSoul Jan 28 '20 at 07:54
  • @ srinivasy i have tried few things, i have removed "next" moreover i have tried these queries 1--$match: {"_id" : mongoose.Types.ObjectId(adminId)}, 2---$match: {"_id" :adminId }, 3--$match: {_id : mongoose.Types.ObjectId(adminId)}(without double quotes) ,4--$match: {"_id" : _id}, 1,2,3 queries are returning empty object i.e{}, 4th query return empty array [](when i send _id from postman instead of dealer id & i have changed const{_id}:req.body) BUT the query is working perfectly fine in mongoshell – sachin.pandey Jan 28 '20 at 09:26
  • @sachin.pandey : aggregate will never return `{}`, it will always return `[]` of objects, So are you connecting to right DB & collection, did you check DB name & collection name in code? Also is your `req.body.adminID` match to any `_id` of user collection ? – whoami - fakeFaceTrueSoul Jan 28 '20 at 15:48
  • exports.vendorWiseIndent = async (req, res) => { const { _id } = req.body try { const order = await Master.aggregate([ { $match: { _id: _id....REST EVERYTHING IS EXACTLY SAME i have pasted your code and just ti avoid any mismatch between id's for testing purpose i am sending "_id" now my POSTMAN REQUEST: { "_id": "5e2554ec3405363bc4bf86c0"} POSTMAN RESPONSE:{ "order": [] } db connection string:mongoose.connect('mongodb://127.0.0.1:27017/shopApp'...... thats my database.. there has to be some issue – sachin.pandey Jan 29 '20 at 06:09
  • @sachin.pandey : Are you connecting to right DB ? Did you check db name ? Also just try plain ‘.find()’ with that ‘_id’ and check if any doc being returned or not, Or since there is a working query - please raise a seperate question with all the code since we’ve a working query let’s see when in code it’s going wrong.. – whoami - fakeFaceTrueSoul Jan 29 '20 at 06:11
  • 1
    yes db is right .. it wud be better if i post a this a question i will paste the link in the comments please have a look at it – sachin.pandey Jan 29 '20 at 06:55
  • https://stackoverflow.com/questions/59962164/query-working-in-mongoshell-but-not-in-nodejs .. please have a look at it – sachin.pandey Jan 29 '20 at 07:19
  • @ – srinivasy require mongoose was missing i am geeting the response now one more thing i am getting orders as "orders": [ { "_id": "5e2564323405363bc4bf86c6", "isApproved": false, "orderCreatedOn": "2020-01-20T08:26:26.812Z" }, but suppose i need to send just isApproved inside a single object array like this { "phoneNo": 9992625542, "name": "vendor5", "address": "5 vendor address 5", "depotCode": "D3139", "isApproved": false – sachin.pandey Jan 29 '20 at 09:33
  • @sachin.pandey : I had given you that `require` as well :-) , So regarding `orders` you're getting orders as an array with multiple objects, then how could you send one field `isApproved` ? which `isApproved` has to be picked out of two objects in `orders` array ? – whoami - fakeFaceTrueSoul Jan 29 '20 at 15:43
  • 1
    yes @srinivasy i later was able to resolve that.. thanks for your help that sloved my issue – sachin.pandey Jan 30 '20 at 11:11
  • Hi @@ – srinivasy can you please look at this question https://stackoverflow.com/questions/60034822/sum-aggregation-in-mongodb-nodej-driver see if u can help me – sachin.pandey Feb 03 '20 at 10:47