Как я могу получить mon go документы с несколькими неэксклюзивными селекторами, используя Mon goose? - PullRequest
1 голос
/ 10 февраля 2020

Мне нужно создать один запрос для возврата:

  • Документы с их идентификаторами (необязательно)
  • Документы, соответствующие строке текстового поиска (необязательно)
  • Другие документы, отсортированные по количеству баллов и числу которых ограничено целочисленным аргументом

Общий лимит - это предоставленный + длина идентификаторов массива документов первого условия.

Раньше я работал с метеором, где можно возвращать массив запросов курсоров. В этом случае я работаю с бэкэндом mon goose и не уверен, что делать дальше. Я предполагаю, что мне нужно использовать Model.aggregate и предоставить мои условия в виде массива. Однако запрос завершается неудачно с ошибкой Arguments must be aggregate pipeline operators.

Каждое из моих условий отлично работает индивидуально с обычным запросом find().

Вот мой обработчик запросов graphQL, где я не могу найти, что идет не так:

              async (root, { search, selected = 0, limit = 10 }, { models: { tag } }) => {
               try {
                   let selector = [{}] // {} should return the documents by default if no other condition is set
                   if (selected.length) selector.push({ _id: { $in: selected } })
                   if (search && search.length) selector.push({
                       $text: {
                           $search: search,
                           $caseSensitive: false,
                           $diacriticSensitive: false
                       }
                   })

                   const tags = await tag.aggregate(selector).sort('-score').limit(limit + selected.length)

                   return {
                       ok: true,
                       message: "Tags fetched",
                       data: tags
                   }
               } catch (err) { return { ok: false, message: err.message }; }
           }
       ),

Когда я регистрирую селектор со всеми установленными аргументами, он возвращает массив следующая форма:

[
  {},
  { _id: { '$in': [Array] } },
  {
    '$text': {
      '$search': 'test',
      '$caseSensitive': false,
      '$diacriticSensitive': false
    }
  }
]

ОБНОВЛЕНИЕ

На основе ответа @Ashh с дополнительным оператором $or полная переменная агрегатора выглядит следующим образом:

   {
    '$match': {
      '$or': {
        _id: {
          '$in': [ '5e39745e0ac14b1731a779a3', '5e39745d0ac14b1731a76984' ]
        },
        '$text': {
          '$search': 'test',
          '$caseSensitive': false,
          '$diacriticSensitive': false
        }
      }
    }
  },
  { '$sort': { score: -1 } },
  { limit: 12 }

Я все еще получаю ошибку «Аргументы должны быть агрегированными операторами конвейера», и я не вижу, где, если аргумент $text отсутствует, я получаю документы по умолчанию по количеству очков.

@ Эш, я подожду твоего обновленного ответа, чтобы подтвердить его. Еще раз спасибо за вашу помощь.

1 Ответ

1 голос
/ 10 февраля 2020

Mon goose aggregate() использует этап $match, который эквивалентен find(), но принимает некоторые этапы в виде массива элементов для фильтрации документов. Вы можете проверить пример здесь Mongoose Aggregate.

И отдых - ваш код ошибки. Это должно быть

async (root, { search, selected = 0, limit = 10 }, { models: { tag } }) => {
  try {
    const aggregate = []
    let selector = { $match: { }};
    aggregate.push(selector)
    if (selected.length) {
      aggregate[0].$match['$or'] = [];
      aggregate[0].$match.$or.push({ _id: { $in: selected }});
    }
    if (search && search.length) {
      aggregate[0].$match['$or'] = aggregate[0].$match['$or'] ? aggregate[0].$match['$or'] : []
      aggregate[0].$match.$or.push({ $text: {
        $search: search,
        $caseSensitive: false,
        $diacriticSensitive: false
      }})
    }
    aggregate.push({ $sort: { score: - 1 }})
    aggregate.push({ $limit: limit })
    const tags = await tag.aggregate(aggregate)
    return {
      ok: true,
      message: "Tags fetched",
      data: tags
    };
  } catch (err) {
    return { ok: false, message: err.message };
  }
};
...