Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit MongoDB aggregation $lookup to only 1 match

There are two collections, users and reports.

My goal is to make an aggregation that gets all users and for each user includes the amount of user's last report.

Here is my current aggregation:

db.users.aggregate([{
  $lookup: {
    from: 'reports',
    localField: '_id',
    foreignField: 'userId',
    as: 'report',
  },
}, {
  $project: {
    'lastReportAmount': {
      $let: {
        vars: {
          lastReport: {'$arrayElemAt': ['$report', 0]},
        },
        in: '$$lastReport.amount',
      },
    },
    'id': '$_id',
    'name': 1,
    'firstLogin': 1,
    'email': 1,
  },
}])

This query works correctly, BUT it's very slow.
The reason for that is that $lookup returns all reports that match a certain userId, instead of one (last).

Is there a way to limit the $lookup to only one match?

like image 584
Michael Avatar asked Mar 22 '18 12:03

Michael


1 Answers

You can try the new lookup variant available in 3.6.

Add an index on the userId and date field in reports collection and see if it gets picked up.

db.users.aggregate([
 {"$lookup":{
    "from": "reports",
    "let": {"_id":"$_id"},
    "pipeline":[
      {"$match":{"$expr":{"$eq":["$$_id","$userId"]}}},
      {"$sort":{"date": -1}},
      {"$limit":1}
    ],
    "as": "lookup-latest"
 }},
 {"$project": {
    'lastReportAmount':{'$arrayElemAt':['$lookup-latest', 0]},
    'id': '$_id',
    'name': 1,
    'firstLogin': 1,
    'email': 1
 }}
])
like image 81
s7vr Avatar answered Nov 02 '22 09:11

s7vr