Adding multiple clauses to EmbeddedDocuments

Hey I have a problem with my aggregation search. following statement gives me the proper result. just additionally i need to specify not deleted elements. I need to specify that produces and companies are different collections.

[
  {
    '$search': {
      'index': 'company_index', 
      'compound': {
        'should': [
          {
            'autocomplete': {
              'path': 'companyName', 
              'query': 'apple'
            }
          }, {
            'embeddedDocument': {
              'path': 'produces', 
              'operator': {
                'compound': {
                  'must': [
                    {
                      'autocomplete': {
                        'path': 'produces.name', 
                        'query': 'apple', 
                        'fuzzy': {
                          'maxEdits': 2, 
                          'prefixLength': 3
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        ]
      }
    }
  }, {
    '$match': {
      'status': 'VERIFIED'
    }
  }, {
    '$skip': 0
  }, {
    '$limit': 24
  }, {
    '$project': {
      'companyName': 1, 
      'status': 1, 
      'score': {
        '$meta': 'searchScore'
      }
    }
  }
]

So when i add this statement into must it gives me no result, what am i doing wrong at this point ?

  {
                      'equals': {
                        'path': 'produces.deleted', 
                        'value': false, 
   }

Hi @Atakan_Yildirim,

So when i add this statement into must it gives me no result, what am i doing wrong at this point ?

Can you provide the following information:

  1. 3-4 Sample documents
  2. Index definition
  3. Output after using the current pipeline without the "produces.deleted" value of false in the must clause.
  4. The expected output of the sample documents provided

Please redact any personal or sensitive information before positing it here.

In the meantime, I have tried to replicate a similar pipeline in my test environment for demonstration purposes using embeddedDocuments with the below search

index definition:

{
  "mappings": {
    "fields": {
      "companyName": {
        "type": "autocomplete"
      },
      "produces": {
        "dynamic": false,
        "fields": {
          "deleted": {
            "type": "boolean"
          },
          "name": {
            "type": "autocomplete"
          }
        },
        "type": "embeddedDocuments"
      }
    }
  }
}

Sample documents:

apples> db.collection.find()
[
  {
    _id: ObjectId("6387d384a44f9420fbc4e1e6"),
    companyName: 'apple',
    produces: [ { name: 'apple', deleted: false } ],
    status: 'VERIFIED'
  },
  {
    _id: ObjectId("6387d384a44f9420fbc4e1e7"),
    companyName: 'apple',
    produces: [ { name: 'delicious apples', deleted: true } ],
    status: 'VERIFIED'
  },
  {
    _id: ObjectId("6387d384a44f9420fbc4e1e8"),
    companyName: 'apples are good',
    produces: [ { name: 'apple test', deleted: false } ],
    status: 'VERIFIED'
  }
]

Slightly altered pipeline using "produces.deleted" search for false in the must clause (did not include the $match , $skip or $limit for brevity:

var pipeline = 
[
  {
    '$search': {
      index: 'company_index',
      compound: {
        should: [
          { autocomplete: { path: 'companyName', query: 'apple' } },
          {
            embeddedDocument: {
              path: 'produces',
              operator: {
                compound: {
                  must: [
                    {
                      autocomplete: {
                        path: 'produces.name',
                        query: 'apple',
                        fuzzy: { maxEdits: 2, prefixLength: 3 }
                      }
                    },
                    {
                      equals: { path: 'produces.deleted', value: false }
                    }
                  ]
                }
              }
            }
          }
        ]
      }
    }
  },
  {
    '$project': {
      companyName: 1,
      status: 1,
      'produces.deleted': 1,
      'produces.name': 1,
      score: { '$meta': 'searchScore' }
    }
  }
]

Output from running above search pipeline:

apples> db.collection.aggregate(pipeline)
[
  {
    _id: ObjectId("6387d384a44f9420fbc4e1e8"),
    companyName: 'apples are good',
    produces: [ { name: 'apple test', deleted: false } ],
    status: 'VERIFIED',
    score: 2.1154866218566895
  },
  {
    _id: ObjectId("6387d384a44f9420fbc4e1e6"),
    companyName: 'apple',
    produces: [ { name: 'apple', deleted: false } ],
    status: 'VERIFIED',
    score: 2.098456382751465
  },
  {
    _id: ObjectId("6387d384a44f9420fbc4e1e7"),
    companyName: 'apple',
    produces: [ { name: 'delicious apples', deleted: true } ],
    status: 'VERIFIED',
    score: 0.09845632314682007
  }
]

Regards,
Jason

Hey Jason thank you for your brief example and information it helped a lot, now i will try your samples if they dont work i will send sample output for further support :slight_smile:

1 Like

Hey Jason you can see my mapping here i think its the issue thats why whenever i add produces.deleted to search query it returns nothing.

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "companyName": [
        {
          "analyzer": "lucene.standard",
          "type": "string"
        },
        {
          "foldDiacritics": true,
          "maxGrams": 6,
          "minGrams": 2,
          "tokenization": "edgeGram",
          "type": "autocomplete"
        }
      ],
      "produces": {
        "type": "embeddedDocuments",
        "fields": {
          "name": [
            {
              "analyzer": "lucene.standard",
              "type": "string"
            },
            {
              "foldDiacritics": true,
              "maxGrams": 6,
              "minGrams": 2,
              "tokenization": "edgeGram",
              "type": "autocomplete"
            }
          ]
        }
      },
      "status": {
        "type": "string"
      }
    }
  }
}

So my following questiong how can i add produces.deleted to this mapping on mongodb ? Because they are not using this code so they must be handled mappings on mongodb side.

1 Like

Additionally can you tell me where can i update my index definition?

I’m not entirely sure what your document structure is like but I will presume the "deleted" field exists within the objects inside of the "produces" array. Please correct me if I am wrong here.

You can test the following index definition (This was based off the index definition you had posted here but with an added a boolean type index definition for the "deleted" field inside the "produces" array embedded documents):

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "companyName": [
        {
          "analyzer": "lucene.standard",
          "type": "string"
        },
        {
          "foldDiacritics": true,
          "maxGrams": 6,
          "minGrams": 2,
          "tokenization": "edgeGram",
          "type": "autocomplete"
        }
      ],
      "produces": {
        "fields": {
          "deleted": {
            "type": "boolean"
          },
          "name": [
            {
              "analyzer": "lucene.standard",
              "type": "string"
            },
            {
              "foldDiacritics": true,
              "maxGrams": 6,
              "minGrams": 2,
              "tokenization": "edgeGram",
              "type": "autocomplete"
            }
          ]
        },
        "type": "embeddedDocuments"
      },
      "status": {
        "type": "string"
      }
    }
  }
}

Additionally can you tell me where can i update my index definition?

As of the time of this message you can’t use the Atlas UI Visual Index Builder to define fields of embeddedDocuments type so you will need to do so using the JSON editor in the Atlas UI.

Also, as noted in the embeddedDocument documentation currently the Atlas Search embeddedDocuments index option, embeddedDocument operator, and embedded scoring option are in preview.

Regards,
Jason