Если вам нужно вычислить что-то подобное во время выполнения, с «фильтруется» контента из массива, определяющего порядок сортировки, то вам лучше сделать что-то с .aggregate()
, чтобы изменить форму и определить значение сортировки так:
db.collection.aggregate([
// Pre-filter the array elements
{ "$project": {
"tags": 1,
"score": {
"$setDifference": [
{ "$map": {
"input": "$tags",
"as": "tag",
"in": {
"$cond": [
{ "$eq": [ "$$el.id", "t1" ] },
"$$el.score",
false
]
}
}},
[false]
]
}
}},
// Unwind to denormalize
{ "$unwind": "$score" },
// Group back the "max" score
{ "$group": {
"_id": "$_id",
"tags": { "$first": "$tags" },
"score": { "$max": "$score" }
}},
// Sort descending by score
{ "$sort": { "score": -1 } }
])
Если первая часть трубопровода используется для «предварительного фильтра» содержание массива (а также сохраняя исходное поле) для просто эти значения «score», где id равен «t1». Это делается путем обработки $map
, которая применяет условие к каждому элементу через $cond
, чтобы определить, следует ли возвращать «счет» для этого элемента или false
.
$setDifference
операция делает сравнение с одним массивом [false]
элемента, который эффективно удаляет любые false
значения, возвращенные из $map
. В качестве «набора» это также удаляет повторяющиеся записи, но для цели сортировки здесь это хорошо.
С уменьшенным и измененным массивом к значениям, которые вы обрабатываете $unwind
готовы к следующему этапу для обработки значений как отдельных элементов. Этап $group
по существу применяет $max
к «оценке», чтобы вернуть максимальное значение, содержащееся в отфильтрованных результатах.
Тогда речь идет только о применении $sort
по определенному значению для оформления документов. Естественно, если вы хотите, чтобы это было наоборот, используйте $min
и сортируйте в порядке возрастания.
Конечно, добавьте этап $match
в начало, если все, что вам действительно нужно, это документы, которые на самом деле содержат значения «t1» для id
в тегах. Но эта часть имеет наименьшее значение для сортировки по отфильтрованным результатам, которые вы хотите достичь.
Альтернативой вычислению является выполнение всего этого при записи записей в массив в документах. Вид сумбурно, но это идет что-то вроде этого:
db.collection.update(
{ "_id": docId },
{
"$push": { "tags": { "id": "t1", "score": 60 } },
"$max": { "maxt1score": 60 },
"$min": { "mint1score": 60 }
}
)
Здесь оператор $max
обновления только устанавливает значение указанного поля, если новое значение больше, чем существующее значение или в противном случае свойства еще не существует. Обратный случай относится к $min
, где только если оно меньше, чем оно будет заменено новым значением.
Это, конечно, иметь эффект добавления различных дополнительных свойств документов, но конечный результат сортировки значительно упрощается:
db.collection.find().sort({ "maxt1score": -1 })
И это будет работать намного быстрее, чем вычисление с агрегацией трубопровод.
Так что рассмотрите принципы дизайна. Структурированные данные в массивах, в которых вы хотите отфильтровать и парные результаты для сортировки, вычисляют во время выполнения, чтобы определить, какое значение нужно сортировать. Добавление дополнительных свойств в документ по адресу .update()
означает, что вы можете просто ссылаться на эти свойства, чтобы напрямую сортировать результаты.
Возможно, возник вопрос более ясный, если образец массива содержал другие значения, а не только «t1» и, возможно, несколько документов и ожидаемый результат. Но я думаю, что вижу, к чему вы клоните. –