Search code examples
mongoosemongodb-atlasmongodb-atlas-search

MongoDB Atlas Search by referenced document field search term


I know how to use MongoDB Atlas search to search for Orders by it's name and a given Buyer ID, along with a known/matched Supplier name For example:

(Using Mongoose ODM)

    const searchResults = await Order.aggregate([
    {
      $search: {
        text: {
          query: '{search-term}',
          path: 'name',
          fuzzy: {
            maxEdits: 2,
            maxExpansions: 100,
          },
        },
      },
    },
    { $unwind: '$supplier' },
    {
      $lookup: {
        from: 'suppliers',
        localField: 'supplier',
        foreignField: '_id',
        as: 'suppliers',
      },
    },
    {
      $match: {
        buyer: mongoose.Types.ObjectId('5e19a594c86e72017debf9dc'),
        // The search term entered by a user:
        'suppliers.name': 'supplierName',
      },
    },
  ]);

However, I'd like to be able to utilise MongoDB Atlas search to:

  • search for all Orders,
  • given a Buyer ID,
  • where the search term - may not be a full match -is a Supplier name,
  • where Buyer and Supplier are nested on Order by referenced IDs:

Having an Order schema:

const orderSchema = new mongoose.Schema({
  name: {
    type: String,
    minlength: 2,
    maxlength: 255,
  },
  buyer: { type: ObjectId, ref: 'Buyer' },
  supplier: { type: ObjectId, ref: 'Supplier' },
});

Buyer schema:

const buyerSchema = new mongoose.Schema({
  name: {
    type: String,
  },
  ...
});

Supplier schema:

const supplierSchema = new mongoose.Schema({
  name: {
    type: String,
  },
  ...
});

Solution

  • This should work using compound, text and equals in $search:

    const order = await Order.aggregate([
    { $search: {
        compound: {
            must: [ 
                { text: { query: "SEARCH TERM", path: "name"}}, 
                { equals: { path: "buyer", value: ObjectId("5e19a594c86e72017debf9dc") }} 
            ]
        }
    }}])
    

    You could also move the equals query to a filter clause if you don't want it to impact your scoring.