Я пытаюсь вычислить значение пропуска для данной записи в коллекции mongo db с использованием драйвера php. Поэтому, беря заданную запись, узнайте индекс этой записи во всей коллекции. Это возможно?
В настоящее время я выбираю все записи и вручную делаю индекс по массиву результатов.
Это называется «прямой пейджинг», который представляет собой концепцию, которую вы можете использовать для «эффективной страницы» посредством результатов в «прямом» направлении при использовании «отсортированных» результатов.
Включена логика JavaScript (потому что она работает в оболочке), но не сложно перевести.
Концепция в целом:
{ "_id": 1, "a": 3 }, { "_id": 2, "a": 3 }, { "_id": 3, "a": 3 }, { "_id": 4, "a": 2 }, { "_id": 5, "a": 1 }, { "_id": 6, "a": 0 }
Рассмотрите эти «уже отсортированные» документы (для удобства) в качестве примера результатов, которые мы хотим «на странице» на «два» элемента на странице.
В первом случае вы делаете что-то вроде этого:
var lastVal = null, lastSeen = []; db.collection.find().sort({ "a": -1 }).limit(2).forEach(function(doc) { if ( lastVal != doc.a ) { lastSeen = []; } lastVal = doc.a; lastSeen.push( doc._id ); // do something useful with each document matched });
Теперь эти lastVal
и lastSeen
– это то, что вы храните в чем-то вроде «переменной сеанса», чем можно получить при следующем запросе с точки зрения веб-приложений или в противном случае что-то подобное, если нет.
То, что они должны содержать, это самое последнее значение, которое вы сортировали, и список «уникальных» значений _id
которые были замечены, поскольку это значение не изменилось. Следовательно:
lastVal = 3, lastSeen = [1,2];
Дело в том, что когда приходит запрос на «следующую страницу», вы хотите использовать эти переменные для чего-то вроде этого:
var lastVal = 3, lastSeen = [1,2]; db.collection.find({ "_id": { "$nin": lastSeen }, "a": { "$lte": lastVal } }).sort({ "a": -1 }).limit(2).forEach(function(doc) { if ( lastVal != doc.a ) { lastSeen = []; } lastVal = doc.a; lastSeen.push( doc._id ); // do something useful with each document matched });
Что это значит, «исключить» все значения _id
, которые записаны в lastSeen
из списка результатов, а также убедиться, что все результаты должны быть «меньше или равно» (убывающий порядок) lastVal
записанный для сортировки поле «a».
Это дает следующие два результата в коллекции:
{ "_id": 3, "a": 3 }, { "_id": 4, "a": 2 },
Но после обработки наши значения теперь выглядят так:
lastVal = 2, lastSeen = [4];
Итак, теперь логика вытекает из того, что вам не нужно исключать другие значения _id
увиденные ранее, так как вы действительно ищете только значения «a», чем «меньше или равно» lastVal
и поскольку существует только «один», _id
увиденное при этом значении, тогда только исключить это.
Это, конечно, дает следующую страницу, используя тот же код, что и выше:
{ "_id": 5, "a": 1 }, { "_id": 6, "a": 0 }
Это самый эффективный способ «переслать страницу» по результатам в целом и особенно полезен для эффективного поискового вызова «отсортированных» результатов.
Если, однако, вы хотите «перейти» на страницу 20
или подобное действие на любом этапе, то это не для вас. Вы придерживаетесь традиционного .skip()
и .limit()
чтобы иметь возможность сделать это с помощью «номера страницы», поскольку нет другого рационального способа «рассчитать» это.
Так что все зависит от того, как ваше приложение реализует «пейджинг» и с чем вы можете жить. .skip()
и .limit()
страдают от производительности «пропусков» и их можно избежать, используя подход здесь.
С другой стороны, если вы хотите «перейти на страницу», то «пропуск» – это ваш единственный реальный вариант, если вы не хотите создать «кеш» результатов. Но это еще одна проблема.