#mongodb #find #key #document #substr
Вопрос:
Я рассмотрел множество решений, но все они включают поиск подстрок в значениях полей. У меня есть коллекция, в которой более 3 миллионов документов, и в некоторых из них есть поля даты, но не все, и не одинаковое количество полей в каждом. Например, у одного может быть «Дата первого дня» и «Дата последнего дня», другие могут содержать только «Дату», а другие могут вообще не содержать полей даты.
Что я хочу сделать, так это запросить все документы, в которых в ключах полей есть слово/подстрока «дата». Другими словами, запросите все ключевые поля, содержащие подстроку «дата». Например:
db.collection.find({ *date* : { $exists : true } })
.projection({})
.sort({_id:-1})
(Я знаю, что * неправильно, но это просто для иллюстрации)
Я пробовал использовать .find()
, .aggregate()
и $regex
, но все синтаксисы, которые я пробовал, вообще не имеют смысла…
Ответ №1:
Это может быть достигнуто с помощью конвейера агрегирования. Давайте предположим, что ваша коллекция выглядит так:
[
{
"_id": 1,
property: true,
},
{
"_id": 2,
firstDate: "First date"
},
{
"_id": 3,
lastDate: "Last name"
},
{
"_id": 4,
date: "date"
},
{
"_id": 5,
property: true
},
{
"_id": 6,
name: "Name"
}
]
Сначала вам нужно создать свойство с массивом ключей и значений, чтобы позже вы могли фильтровать по ключам. Это можно сделать, используя $objectToArray
в an $addFields
.
db.collection.aggregate([
{
$addFields: {
keysAndValues: {
$objectToArray: "$ROOT",
}
}
}
]);
Если вы перейдете $$ROOT
к нему, вы создадите массив со всеми ключами и значениями документов. Таким образом, ваши данные на данный момент будут выглядеть следующим образом:
[
{
"_id": 1,
"keysAndValues": [
{
"k": "_id",
"v": 1
},
{
"k": "property",
"v": true
}
],
"property": true
},
...
{
"_id": 6,
"keysAndValues": [
{
"k": "_id",
"v": 6
},
{
"k": "name",
"v": "Name"
}
],
"name": "Name"
}
]
Таким образом, теперь вы можете добавить $match
этап, используя $regex
фильтр по ключам, например:
db.collection.aggregate([
{
$addFields: {
keysAndValues: {
$objectToArray: "$ROOT",
}
}
},
{
$match: {
"keysAndValues.k": {
$regex: "date",
$options: "i",
}
}
}
]);
На этом этапе у вас уже был бы желаемый результат, все документы, в которых есть слово date
в ключах, тогда вы могли бы просто отключить созданное вами свойство, чтобы сделать возможной фильтрацию keysAndValues
, для очистки данных.
db.collection.aggregate([
{
$addFields: {
keysAndValues: {
$objectToArray: "$ROOT",
}
}
},
{
$match: {
"keysAndValues.k": {
$regex: "date",
$options: "i",
}
}
},
{ $unset: 'keysAndValues' },
]);
После этого ваш окончательный результат будет:
[
{
"_id": 2,
"firstDate": "First date"
},
{
"_id": 3,
"lastDate": "Last name"
},
{
"_id": 4,
"date": "date"
}
]
Вы можете увидеть рабочий пример на этой игровой площадке:
https://mongoplayground.net/p/U5FjTOVQIwb