Сложный запрос mongodb с объектами с разными именами ключей и массивами

#node.js #mongodb

#node.js #mongodb

Вопрос:

Мой вопрос состоит из двух частей. Моя структура документа приведена ниже.

  1. По сути , я хотел бы запросить элементы массива foo.*.bar.* . Как я могу получить доступ bar к запросу, если ключи foo (т. Е. родительский элемент bar ) различны для каждого документа?
  2. В частности, bar это массив переменной длины. Элементы, которые bar могут храниться, относятся к фиксированному набору (например cat , dog , cow и т.д.). И bar может иметь любое их количество, в любом порядке. Я хотел бы запросить: документы, в которых есть только один bar , содержащий один или несколько определенных элементов. Например. cat => Это вернет документ № 2. (Несмотря на то, что он имеет два cats в одном bar , у него есть только один bar с. cats

Чтобы сделать это более понятным, вот псевдокод для предиката: I

 predictate(document, item):
    bars_which_contain_item = 0
    foreach currentFoo in document.foo:
       if currentFoo.bar.contains(item) bars_which_contain_item  = 1
    return bars-which-contain-item == 1;
 
 

Я просмотрел документацию, касающуюся запросов к массивам, встроенным документам и массивам встроенных документов, но не смог найти ответа. Возможно ли то, что я хочу сделать? Или мне нужно добавить проход, который проходит через все мои данные и добавляет поля numberOfCats, numberofDogs, numberOfCows, чтобы разрешить такого рода запросы в будущем? (Мне не нужно будет часто выполнять такого рода запросы, а производительность не слишком важна).

PS Я использую nodejs, но я думаю, что структура запроса не изменится слишком сильно. (Кроме того, если я могу выполнить запрос в MongoDB Compass, это еще лучше).

 {
   _id: 1,
   foo: {
      a : { bar: ['cat', 'dog', 'cow'] },
      b : { bar: ['cat', 'cat', 'dog'] },
   }
},
{
   _id: 2,
   foo: {
      c : { bar: ['cow'] },
      d : { bar: ['dog'] },
      e : { bar: ['cow'] },
      f : { bar: ['cat', 'dog', 'cat'] },
   }
},
{
   _id: 3,
   foo: {
      g : { bar: ['cat', 'cow'] },
      h : { bar: ['cow'] },
      i : { bar: ['cat'] },
   }
}
 

Ответ №1:

Для вашего первого вопроса используйте https://docs.mongodb.com/manual/reference/operator/aggregation/objectToArray /.

 r = db.foo.aggregate([
  {$project: {foo: {$objectToArray: '$foo'}}},
  {$project: {foo: '$foo.v'}},
])

# =>

{"_id":1,"foo":[{"bar":["cat","dog","cow"]},{"bar":["cat","cat","dog"]}]}
{"_id":2,"foo":[{"bar":["cow"]},{"bar":["dog"]},{"bar":["cow"]},{"bar":["cat","dog","cat"]}]}
{"_id":3,"foo":[{"bar":["cat","cow"]},{"bar":["cow"]},{"bar":["cat"]}]}

 

Что касается вашего второго вопроса:

 
r = db.foo.aggregate([
  {$project: {foo: {$objectToArray: '$foo'}}},
  {$project: {foo: '$foo.v'}},
  {$project: {foo: {$cond: {
    if: {eq: ['cat', '$foo.bar']},
    then: '$foo.bar',
    else: '$REMOVE',
  }}}},
  {$project: {foo: {$filter: {
    input: '$foo',
    as: 'x',
    cond: {$in: ['cat', '$x']},
  }}}},
  {$match: {foo: {$size: 1}}},
])


{"_id":2,"foo":[["cat","dog","cat"]]}

 

Комментарии:

1. вау, спасибо, мне потребуется некоторое время, чтобы переварить это.