0

what I am trying to do , is to join two collections and then return elements whome names exist inside an array

these are the models

CarModel

id,
carAuthorizedDrivers:[String],
garageId:{type: Schema.ObjectId,ref:"garage"}

driversModel

id,
garageId:{type: Schema.ObjectId,ref:"garage"}
drivers:[{name:String,skill:String}]

this is the result of the join

{
"id":"1D99399379773",
"carAuthorizedDrivers":["DriverA","DriverB"],
"garageId":"010003",
"JoinDrivers":[drivers:[{"name":"DriverA","skill":"89"},{"name":"DriverB","skill":"77"},{"name":"DriverC","skill":"45"}]]
}

I want to restrict Joindrivers for the purpose of only showing drivers(name+skills) whome names belong to carAuthorizedDrivers , so I want joinDrivers to contain only the following :

{"name":"DriverA","skill":"89"},{"name":"DriverB","skill":"77"}

what i tried to do is the following :

join () {
    return new Promise(function (resolve, reject) {
      Car.aggregate([
        {
          $lookup: {
            from: 'drivers', // collection name in db
            localField: 'garage_id',
            foreignField: 'garage_id',
            as: 'joinDrivers'
          }
        },
        { $unwind: '$Joindrivers' },
        { $unwind: '$Joindrivers.drivers' },
        { $unwind: '$carAuthorizedDrivers' },
        { $match: { 'Joindrivers.drivers.name': { $in: 'carAuthorizedDrivers' } } }
      ]).exec((err, result) => {
        if (err) {
          reject(err)
        }
        resolve(result)
      })
    })
  }

I get $in needs an array ERROR , but if I put an Array manually like this :

$match: { 'Joindrivers.drivers.name': { $in: ["DriverA","DriverB"] } }  

$in works well and I get the result , how do I solve this issue ?

2 Answers 2

5

To compare or match two document fields within an aggregation's $match stage, you have to use an aggregation operator $in (not the query language operator $in). And, to use the aggregation operator in the $match stage, you must use the $expr operator.

So, your match stage should be:

{ $match: { $expr: { $in: [ "$Joindrivers.drivers.name", "$carAuthorizedDrivers" ] } } }



The following code uses the output from the lookup stage to filter based on the provided condition:

db.collection.aggregate( [
{ $unwind: "$JoinDrivers" },
{ $addFields: { 
       "JoinDrivers.drivers": {
            $filter: {
                input: "$JoinDrivers.drivers", as: "driver",
                cond: {
                    $in: [ "$$driver.name", "$carAuthorizedDrivers" ] 
                }
            }
       }
}},
] )
Sign up to request clarification or add additional context in comments.

11 Comments

This didn't work , it returned : $in requires an array as a second argument, found: string
Is this field carAuthorizedDrivers an array?
You can comment the { $unwind: '$carAuthorizedDrivers' }, and try; it will work.
If you want to keep the { $unwind: '$carAuthorizedDrivers' } stage, then use this: { $match: { $expr: { $eq: [ "$Joindrivers.drivers.name", "$carAuthorizedDrivers" ] } } }. Please note the $unwind makes the string array into strings.
it repeats the same object twice , let's say a Car has << carAuthorizedDrivers":["DriverA","DriverB"]>> it sends back a Car with "DriverA" inside Joindrivers followed but the same Car with "DriverB" inside Joindrivers
|
0

You mixed the Query operator $in with the Aggregation operator $in

Try this one:

{ $match: { $in: ["$Joindrivers.drivers.name", ["DriverA", "DriverB"] } }  

1 Comment

<<Error : unknown top level operator: $in>> and I want to use carAuthorizedDrivers instead of ['DriverA','DriverB']

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.