#node.js #mongodb #mongodb-query
#node.js #mongodb #mongodb-запрос
Вопрос:
Я выполняю запрос с $ или агрегацией по двум полям в базе данных. Первое условие, которое я хочу быть более релевантным, чем второе, поэтому я хочу сначала отсортировать те, которые соответствуют первому условию, а затем вернуть последнее после.
Вот некоторый код:
const regexp = new RegExp('^' req.query.search, 'i')
const query = {
$or: [{ word: regexp }, { 'lang.english': regexp }],
}
const words = await collection
.find(query, {
collation: {
locale: 'sv',
strength: 1,
},
projection: {
'-_id': 1,
'word': 1,
'lang.english': 1,
'lang.definitionEnglish': 1,
'lang.definition': 1,
},
})
.skip(skips)
.limit(page_size)
.toArray()
Итак, в основном, те результаты, которые совпадают с word
регулярным выражением, должны быть первыми, затем lang.english
Комментарии:
1. Вы также можете попробовать использовать
$facet
для группировки, а затем объединить результирующие значения из каждого аспекта в требуемом порядке.
Ответ №1:
Для начала давайте добавим некоторые данные в тестовую коллекцию MongoDB, чтобы поиграть с ними.
db.test.insertMany([
{ word: 'TEST123', lang: { english: 'wibble1' } },
{ word: 'wibble2', lang: { english: 'Test123' } },
{ word: 'test345', lang: { english: 'wibble3' } },
{ word: 'wibble4', lang: { english: 'testy101' } }
]);
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5f6924b271e546940acc10f7"),
ObjectId("5f6924b271e546940acc10f8"),
ObjectId("5f6924b271e546940acc10f9"),
ObjectId("5f6924b271e546940acc10fa")
]
}
Это имеет ту же структуру, что и указано в вопросе.
Затем мы можем создать агрегированный запрос, который будет соответствовать тому же, что и ваша находка, но на этот раз добавим дополнительное поле, по которому мы можем сортировать. Мы сделаем это 1, если поле word совпадает, затем 2 для чего-либо еще.
db.test.aggregate([
{ $match: { $or: [{ word: regexp }, { 'lang.english': regexp }] } },
{ $addFields: { sortingValue: { $cond: { if: { $regexMatch: { input: "$word" , regex: regexp } }, then: 1, else: 2 } } } }
]);
{
"_id" : ObjectId("5f6924b271e546940acc10f7"),
"word" : "TEST123",
"lang" : {
"english" : "wibble1"
},
"sortingValue" : 1
}
{
"_id" : ObjectId("5f6924b271e546940acc10f8"),
"word" : "wibble2",
"lang" : {
"english" : "Test123"
},
"sortingValue" : 2
}
{
"_id" : ObjectId("5f6924b271e546940acc10f9"),
"word" : "test345",
"lang" : {
"english" : "wibble3"
},
"sortingValue" : 1
}
{
"_id" : ObjectId("5f6924b271e546940acc10fa"),
"word" : "wibble4",
"lang" : {
"english" : "testy101"
},
"sortingValue" : 2
}
Теперь мы можем добавить обычную сортировку, пропуск и ограничение.
var regexp = new RegExp('^' 'test', 'i')
var skip = 0;
var limit = 3;
db.test.aggregate([
{ $match: { $or: [{ word: regexp }, { 'lang.english': regexp }] } },
{ $addFields: { sortingValue: { $cond: { if: { $regexMatch: { input: "$word" , regex: regexp } }, then: 1, else: 2 } } } },
{ $sort: { sortingValue: 1 } },
{ $skip: skip },
{ $limit: limit }
]);
{
"_id" : ObjectId("5f6924b271e546940acc10f9"),
"word" : "test345",
"lang" : {
"english" : "wibble3"
},
"sortingValue" : 1
}
{
"_id" : ObjectId("5f6924b271e546940acc10f7"),
"word" : "TEST123",
"lang" : {
"english" : "wibble1"
},
"sortingValue" : 1
}
{
"_id" : ObjectId("5f6924b271e546940acc10f8"),
"word" : "wibble2",
"lang" : {
"english" : "Test123"
},
"sortingValue" : 2
}