简体   繁体   中英

Query multiple collections at once with MongoDB using aggregate, match and lookup

I'm having a bit of an issue here, as I'm trying to wrap my head around the usage of $lookup when doing a query through multiple collections, as explained here: https://stackoverflow.com/a/43653679 and here: https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/

Got 3 collections:

Users - where can use ' email ' field

Config - where can use ' vpn ' field

Firmware - where can use ' version ' field


My intent is to count the number of users that match these conditions:

  • email =! @yahoo.com,@gmail.com,@hotmail.com
  • vpn is ON
  • version is 123

Can you please help me understand how my query should look? Thanks a lot!

I'm not at my workstation at the moment, but I believe this is what you're looking for.

The links you have addressed above in your question explain perfectly what you're looking to do Just seems you're having difficulty working it out in your head (Which we all do.. I know do a lot)

For future reference this would normally be considered/flagged as a duplicate of the question you referenced but I see you're new here and I'm in a great mood for some reason. Hope this helps and if not let me know! Welcome to the community!

db.Users.aggregate([
    { $match: { email: "test@somemail.com" } }, #Get the users that match the email constraints
    {
        $lookup: { #Get the config document associated to the/each user
            from: "Config",
            localField: "config_id",
            foreignField: "_id",
            as: "config"
        }
    },
    {
        $match: { #limit the configs with VPNs that are "ON"
            "config.vpn": "ON"
        }
    },
    {
        $lookup: { #Get the Firmware associated to the/each User
            from: "Firmware",
            localField: "firmware_id",
            foreignField: "_id",
            as: "firmware"
        }
    },
    {   
        $match: { #Limit to only firmwares that are version 123
               "firmware.version": 123
        }
    },
    $count: { "_id" }
])

This (in theory) would return a document like this:

 { "_id": <the number of Users with specified "email", "vpn", "version"> }

I ended up using a js script. Here's most of it:

let vpnConfigs = dbRefs.Devices.VpnConfig.find({"vpn": "on"}).toArray() 
let firmwareConfigs = dbRefs.Devices.FirmwareConfig.find({"version": "1.2.1"}).toArray()

let tenants = dbRefs.Users.Tenant.find().toArray()

let filteredDevices = vpnConfigs.filter(   vpnConfigModel => firmwareConfigs.some(firmwareConfigModel => vpnConfigModel.parent.id
=== firmwareConfigModel.parent.id) )

let totalDevicesNumber = 0

let filteredTenants = tenants.filter(
    tenant => {
        if(/@psft\.com|@gmail\.com|@yahoo\.com|@maildrop.cc/.test(tenant.ownerEmail)){
            return false;
        }

        return filteredDevices.some(configModel => configModel.tenantId === tenant._id)
        let devicesCount = filteredDevices.filter(configModel => configModel.tenantId === tenant._id).length
        totalDevicesNumber += devicesCount
        return devicesCount > 0
    } )

filteredTenants.map(
    tenant => print(tenant.ownerEmail) )


print(`Found ${filteredTenants.length} tenant(s)`) 
print(`Found ${totalDevicesNumber} device(s)`)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM