Home > Software engineering >  Mongoose - $in doesn't respect order
Mongoose - $in doesn't respect order

Time:01-21

I'm using NestJS with Mongoose, I have 2 Collections, Territories and Clinics

First I search for territories near the user

async findAllByLocation(location: Location) {
    const territories = await this.territoryModel.find({
      location: {
        $near: {
          $geometry: {
            type: 'Point',
            coordinates: [location.lat, location.long],
          },
        },
      },
    });
    return territories.map((territory) => {
      return {
        _id: territory._id,
        name: territory.name,
      };
    });
  }

Then the clinic service utilizes this function to fetch the clinic that have any territory from the returned array

  async getClinicsByLocation(location: any): Promise<any> {
    const territories = await this.territoryService.findAllByLocation(location);
    const clinics = await this.clinicModel.find({
      territory: { $in: territories.map((t) => t._id) },
    });
    return clinics;
  }

My issue now is that the territories array was sorted from the nearest to the farthest but the clinics are in random order so the clinics have territories farther than others in the response

One solution is to get clinics per each territory alone then merge the arrays but it's not time or performance efficient

Any Idea ?

CodePudding user response:

I think you can do it in one aggregation query. Also an input and output example will be helpful.

By the way, for your queries I think you want:

  1. Get all territories near to a position
  2. Return only the _id and name
  3. Search clinics which territory field is the same as the _id from territories.

So I think this can be accomplished in one query like this:

db.territories.aggregate([
  {
    $geoNear: {
      near: {
        type: "Point",
        coordinates: [location.lat, location.long]
      },
      distanceField: "dist.calculated"
    }
  },
  {
    $project: {
      name: 1
    }
  },
  {
    $lookup: {
      from: "clinics",
      localField: "_id",
      foreignField: "territory",
      as: "clinics"
    }
  },
  {
    $unwind: "$clinics" // optional; it depends the output you want
  }
])

And the result is something like:

{
   "_id":2,
   "name":"territory name 2",
   "clinics":{
      "_id":ObjectId("61ea8a20f90aaa6f3e23efac"),
      "territory":2,
      "name":"clinic2"
   }
}{
   "_id":1,
   "name":"territory name 1",
   "clinics":{
      "_id":ObjectId("61ea8a20f90aaa6f3e23efab"),
      "territory":1,
      "name":"clinic1"
   }
}{
   "_id":3,
   "name":"territory name 3",
   "clinics":{
      "_id":ObjectId("61ea8a20f90aaa6f3e23efad"),
      "territory":3,
      "name":"clinic3"
   }
}

I've used mongo $geoNear example as input data and in all executions the order is the same.

  •  Tags:  
  • Related