У меня есть настройки nodejs / mongodb и mongoose. Все последняя версия.
Я вроде "новенький" в NOSQL и пытаюсь переписать его с помощью NOSQL и mongoose ORM с помощью такого SQL-запроса:
select * from documents where count(select * from subdocuments where subdocuments.documentId = documents.id) = 5 order by documents.id desc limit 1
В моем случае (вложенные коллекции) основная структура коллекции:
documents: [{
_id: ObjectId
subdocuments: [{
_id: ObjectId
}]
}]
Поэтому мне нужно получить только один последний объект, у которого есть subdocuments = 5, с помощью функции documents.findOne
mongoose.
Можно ли сделать все эти агрегаты с помощью mongodb / mongoose? Я не могу найти ничего подходящего для моего случая.
Спасибо!
2 ответа
Вы можете использовать оператор $ size для поиска документов с полем массива имеет указанную длину:
await documents.findOne({ subdocuments: { $size: 5 } });
В вашем случае вы хотите получить последний документ с _id
в порядке убывания, чтобы вы могли добавить опцию сортировки к findOne()
:
await documents.findOne({ subdocuments: { $size: 5 } }, {}, { sort: { '_id' : -1 } });
Или же:
await documents.findOne({ subdocuments: { $size: 5 } }).sort({_id: -1});
Чтобы найти документ с длиной вложенных документов меньше 5, вы можете использовать $ где оператор a>:
await documents.findOne({$where: 'this.subdocuments.length<5'}, {}, { sort: { '_id' : -1 } });
Существует оператор по имени $expr
, который позволяет вам использовать агрегационные выражения в языке запросов. Это очень удобно здесь, где вам понадобятся агрегирующие операторы в вашем запросе поиска.
Разобьем ваш запрос на куски для понимания, давайте возьмем проверку
subdocuments.documentId = documents.id
В монго это означает итерацию массива субдокументов для поиска субдокументов, которые удовлетворяют вышеуказанным критериям и могут быть выражены следующим образом с использованием $filter
:
{
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
}
Бит подсчета обычно выражается с помощью $size
оператор, так что принимая результат из вышеупомянутого, этот запрос
count(select * from subdocuments where subdocuments.documentId = documents.id)
Переводится в выражение
{
'$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
}
}
Используйте оператор сравнения $gt
, чтобы выполнить условие
where count(select * from subdocuments where subdocuments.documentId = documents.id) > 5
Так как
{
'$gt': [
{ '$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
} },
5
]
}
Для равенства это просто показать с помощью $eq
{
'$eq': [
{ '$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
} },
5
]
}
Вышеприведенное можно затем использовать с { {X0}} вместе с $ expr as
db.collection.find({
'$expr': {
'$eq': [
{ '$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
} },
5
]
}
})
Сортировка и ограничение выполняются с использованием sort()
и limit()
методы курсора соответственно
db.collection.find({
'$expr': {
'$eq': [
{ '$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
} },
5
]
}
}).sort({ '_id': -1 }).limit(1)
Этот запрос также имеет вариант агрегации. С структурой агрегирования, выражения, используемые в конвейере, похожи.
Часть поиска выполняется в $match
шаг конвейера:
db.collection.aggregate([
{ '$match': {
'$expr': {
'$eq': [
{ '$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
} },
5
]
}
} }
])
Сортировка и ограничение передаются в $sort
и $limit
трубопровод этапы соответственно
db.collection.aggregate([
{ '$match': {
'$expr': {
'$eq': [
{ '$size': {
'$filter': {
'input': '$subdocuments',
'cond': { '$eq': ['$$this._id', '$_id'] }
}
} },
5
]
}
} },
{ '$sort': { '_id': 1 } },
{ '$limit': 1 }
])
Похожие вопросы
Новые вопросы
node.js
Node.js — это основанная на событиях, неблокирующая, асинхронная среда выполнения ввода-вывода, использующая движок Google V8 JavaScript и библиотеку libuv. Он используется для разработки приложений, которые интенсивно используют возможность запуска JavaScript как на стороне клиента, так и на стороне сервера и, следовательно, выигрывают от возможности повторного использования кода и отсутствия переключения контекста.