2

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,
  },
  ...
});
Kuyashii
  • 360
  • 1
  • 4
  • 21

2 Answers2

2

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.

Doug
  • 14,387
  • 17
  • 74
  • 104
0

I've managed to achieve the required result with the following, but it does not use Atlas Search so I would appreciate any further help on how to do so.

const order = await Order.aggregate([
      { $unwind: '$supplier' },
      {
        $lookup: {
          from: 'suppliers',
          localField: 'supplier',
          foreignField: '_id',
          as: 'suppliers',
        },
      },
      {
        $match: {
          buyer: mongoose.Types.ObjectId('5e19a594c86e72017debf9dc'),
          'suppliers.name': new RegExp('^' + supplierName, 'i'),
        },
      },
    ]);
Kuyashii
  • 360
  • 1
  • 4
  • 21