#node.js #mongodb
#node.js #mongodb
Вопрос:
Мой вопрос состоит из двух частей. Моя структура документа приведена ниже.
- По сути , я хотел бы запросить элементы массива
foo.*.bar.*
. Как я могу получить доступbar
к запросу, если ключиfoo
(т. Е. родительский элементbar
) различны для каждого документа? - В частности,
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. вау, спасибо, мне потребуется некоторое время, чтобы переварить это.