skip to Main Content

How to query the "car" collection, which stores a document for every car, and retrieve all cars that include specific keywords in their names. Then, find the latest "carInfo" document for each of these cars and return only the cars that are within a certain distance (X miles) from given coordinates.

Here are the schemas for the relevant collections:

Car Schema:
{
  "_id": "ObjectId",
  "name": "String",
}


CarInfo Schema:
{
  "car": {
    "$ref": "Car"
  },
  "address": {
     "location": {
      "type": "Point",
      "coordinates": [Number]
      }
  },
  "timestamp": "Date",
}

I tried this but I keep getting:
MongoServerError: $geoNear, $near, and $nearSphere are not allowed in this context

db.cars.aggregate([
    {
      $match: {
        name: { $in: KEYWORDS},
      },
    },
    {
      $lookup: {
        from: 'carinfos',
        localField: '_id',
        foreignField: 'car',
        as: 'carInfo',
        pipeline: [{ $sort: { timestamp: -1 } }, { $limit: 1 }],
      },
    },
    {
      $unwind: '$carInfo',
    },
    {
      $match: {
        'carInfo.address.location': {
          $near: {
            $geometry: {
              type: 'Point',
              coordinates: coordinates,
            },
            $maxDistance: 5 * 1609.34,
          },
        },
      },
    }
  ])

2

Answers


  1. let COORDINATES = ....
    let DISTANCE_IN_METERS = ....
    let KEYWORDS = ....
    
    db.carinfos.aggregate([
      {
        $sort: { timestamp: -1 }
      },
      {
        $group: {
          _id: '$car',
          carInfo: { $first: '$$ROOT' }
        }
      },
      {
        $lookup: {
          from: 'cars',
          localField: '_id',
          foreignField: '_id',
          as: 'carDetail'
        }
      },
      {
        $unwind: '$carDetail'
      },
      {
        $match: {
          'carDetail.name': { $in: KEYWORDS }
        }
      },
      {
        $geoNear: {
          near: { type: 'Point', coordinates: COORDINATES },
          distanceField: 'distance',
          maxDistance: DISTANCE_IN_METERS,
          spherical: true
        }
      },
    ]);
    
    Login or Signup to reply.
  2. One option is to do something like this:

    1. Match only carinfos which where in range during the last week
    2. Get their car data
    3. Match only document which have the relevant KEYWORDS
    4. For each relevant document, get the latest location of this car
    5. Keep only documents which are the latest location.
    6. You can format the response if you want
    db.carinfos.aggregate([
      {$geoNear: {
          near: { type: 'Point', coordinates: coordinates},
          distanceField: 'distance',
          maxDistance: DISTANCE_IN_METERS,
          query: {timestamp: {$gte: timestampBeforeLastWeek}}, // for example
          spherical: true
      }},
      {$lookup: {
          from: 'cars',
          localField: 'car',
          foreignField: '_id',
          as: 'carDetail'
      }},
      {$match: {$expr: {$in: [{$first: '$carDetail.name'}, KEYWORDS]}}},
      {$lookup: {
            from: 'carinfos',
            localField: 'car',
            foreignField: 'car',
            as: 'last_id',
            pipeline: [
              { $project: {_id: 0, timestamp: 1}},
              { $sort: { timestamp: -1 } },
              { $limit: 1 },
            ],
       }},
       {$match: {$expr: {$eq: [{$first: "$last_id.timestamp"}, "$timestamp"]}}},
    

    See how it works on the playground example without the $near step as it is not supported

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search