0

I'm trying to achieve reliable sorting and index-supported pagination, while filtering documents by string field, which combines values from multiple source fields.

Given this document

{
    _id: ObjectId(...),
    fields: [
        {"type": "first_name", "value": "FirstName"},
        {"type": "last_name", "value": "LastName"},
        {"type": "phone", "value": "123456789"}
    ],
    "search": "123456789 firstname lastname"
}

i build search field by joining lowercase value from each document in fields array. By using combined field i can filter documents with $regex using only part of the value - for example, this document can match user's input firstname 6789 with following filter:

{
    $and: [
        {search: /firstname/},
        {search: /6789/},
        {fields: {$elemMatch: {value: /firstname/i}}},
        {fields: {$elemMatch: {value: /6789/i}}}
    ]
}

And, as expected, it utilizes {search: 1} index to scan 'search' field, instead of fetching it from collection immediately (https://docs.mongodb.com/manual/reference/operator/query/regex/#index-use):

{'stage': 'FETCH',
 'filter': {'$and': [{'fields': {'$elemMatch': {'value': {'$regex': 'firstname',
       '$options': 'iu'}}}},
   {'fields': {'$elemMatch': {'value': {'$regex': '6789',
       '$options': 'iu'}}}}]},
 'inputStage': {'stage': 'IXSCAN',
  'filter': {'$and': [{'search': {'$regex': 'firstname', '$options': 'u'}},
    {'search': {'$regex': '6789', '$options': 'u'}}]},
  'keyPattern': {'search': 1},
  'indexName': 'search_1',
  'isMultiKey': False,
  'multiKeyPaths': {'search': []},
  'isUnique': False,
  'isSparse': False,
  'isPartial': False,
  'indexVersion': 2,
  'direction': 'forward',
  'indexBounds': {'search': ['["", {})']}}}

Unfortunately, if i try and add sorting by _id, MongoDB doesn't seem to be able to use filter on {_id: 1, search: 1} index:

{'stage': 'FETCH',
 'filter': {'$and': [{'fields': {'$elemMatch': {'value': {'$regex': 'firstname',
       '$options': 'iu'}}}},
   {'fields': {'$elemMatch': {'value': {'$regex': '6789', '$options': 'iu'}}}},
   {'search': {'$regex': 'firstname', '$options': 'u'}},
   {'search': {'$regex': '6789', '$options': 'u'}}]},
 'inputStage': {'stage': 'IXSCAN',
  'keyPattern': {'_id': 1, 'search': 1},
  'indexName': '_id_1_search_1',
  'isMultiKey': False,
  'multiKeyPaths': {'_id': [], 'search': []},
  'isUnique': False,
  'isSparse': False,
  'isPartial': False,
  'indexVersion': 2,
  'direction': 'forward',
  'indexBounds': {'_id': ['[MinKey, MaxKey]'],
   'search': ['[MinKey, MaxKey]']}}}

I can't find exact limitations of $regex regarding compound indexes. Is it possible to achieve this behaviour?

1 Answer 1

0

MongoDB supports full text search natively. According to my reading of this and this, it is possible to define a compound index that starts with a text index and continues with _id in any order (ascending or descending) which should satisfy your query requirements.

Unfortunately, if i try and add sorting by _id, MongoDB doesn't seem to be able to use filter on {_id: 1, search: 1} index:

The index must be defined in the order it will be used. Since filtering happens before sorting, try {search: 1, _id: 1}.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.