Як отримати останні N записів у mongodb?


523

Я не можу ніде знайти це документально. За замовчуванням операція find () отримає записи з самого початку. Як я можу отримати останні N записів у mongodb?

Редагувати: також я хочу повернутий результат, упорядкований від менш пізнього до останнього, а не зворотного.


7
@Haim, будь ласка, конкретно, щоб відповісти, яка частина веб-сторінки вирішує моє питання?
Бен Чен

Привіт @BinChen, у мене є одна і та ж проблема останнім часом, вона вирішена?
Хентон

Відповіді:


736

Якщо я розумію ваше запитання, вам потрібно сортувати у порядку зростання.

Якщо припустити, що у вас є поле для ідентифікації чи дати, яке називається "x", ви б зробили ...

.sort ()


db.foo.find().sort({x:1});

1 буде сортувати по зростанню ( від старого до нового) і -1 буде сортувати по спадаючій ( від нових до старого.)

Якщо ви використовуєте автоматично створене _id поле, у нього вбудована дата ... так що ви можете використовувати це для замовлення за ...

db.foo.find().sort({_id:1});

Це поверне всі ваші документи, відсортовані від найдавніших до найновіших.

Природний орден


Ви також можете використовувати природний порядок, згаданий вище ...

db.foo.find().sort({$natural:1});

Знову ж таки, використовуючи 1 або -1 залежно від потрібного замовлення.

Використовувати .limit ()


Нарешті, добре застосовувати обмеження під час виконання такого роду широко відкритого запиту, щоб ви могли зробити будь-який ...

db.foo.find().sort({_id:1}).limit(50);

або

db.foo.find().sort({$natural:1}).limit(50);

11
@MortezaM. Я впевнений, що ваш порядок запитів змішаний ... ваш sort () має бути запущений останнім, а не спочатку (приблизно як SQL ORDER BY) .find ({}). Skip (1) .limit ( 50) .sort ({"дата": - 1})
Джастін Дженкінс

6
Що б там не було, порядок виклику функцій не повинен мати нічого спільного з кінцевим результатом.
Мортеза Мілані

7
@MortezaM. Звичайно, порядок має значення. item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;Який би не був порядок, який був би результат ??? Я погоджуюся з вами, що цей перевернутий порядок не є інтуїтивно зрозумілим. Адже це не SQL, адже він повинен відповідати нормальним парадигмам ОО.
RickyA

37
і все-таки порядок НЕ має значення. Все, що вам потрібно зробити, це спробувати, щоб побачити, що це не так. все це викликається курсором і передається серверу, тому сервер обмежує результати свого роду (верхній N), оскільки нічого іншого не має сенсу.
Ася Камський

9
Документи підтверджують, що замовлення не має значення: посилання
JohnnyHK

120

Останні N додані записи, від менш пізніх до останніх, можна побачити за допомогою цього запиту:

db.collection.find().skip(db.collection.count() - N)

Якщо ви хочете їх у зворотному порядку:

db.collection.find().sort({ $natural: -1 }).limit(N)

Якщо ви встановите Mongo-Hacker, ви також можете скористатися:

db.collection.find().reverse().limit(N)

Якщо ви втомитеся постійно писати ці команди, ви можете створювати власні функції у вашому ~ / .mongorc.js. Напр

function last(N) {
    return db.collection.find().skip(db.collection.count() - N);
}

то з оболонки монго просто наберіть last(N)


1
db.collection.find().reverse().limit(1)дає мені помилку... has no method reverse
Сом

@Catfish Ви праві, я щойно помітив, що зворотний () додав [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ), я оновлю свою відповідь. Дякую.
Trasplazio Garzuglio

1
db.getCollection ('COLLECTION_NAME'). find (). пропустити (db.getCollection ('COLLECTION_NAME'). count () - N) працює для мене чудово :)
Spl2nky

Це має бути відповідь на питання, а не відповідь Джастіна Дженкінса.
Jadiel de Armas

На природний порядок не слід покладатися; якщо ви використовуєте набір реплік (і вам слід), різні вузли можуть мати однакові документи, збережені в іншому порядку на диску.
Вінс Боудрен

14

Для отримання останніх N записів ви можете виконати нижче запит:

db.yourcollectionname.find({$query: {}, $orderby: {$natural : -1}}).limit(yournumber)

якщо ви хочете лише один останній запис:

db.yourcollectionname.findOne({$query: {}, $orderby: {$natural : -1}})

Примітка. Замість $ natural ви можете використовувати один із стовпців зі своєї колекції.


це працює для мене db.yourcollectionname.findOne ({$ query: {}, $ orderby: {$ natural: -1}}). Я думаю, останнього parathensis відсутнє у відповіді
Аджай

На природний порядок не слід покладатися; якщо ви використовуєте набір реплік (і вам слід), різні вузли можуть мати однакові документи, збережені в іншому порядку на диску.
Вінс Боудрен

6

ви можете використовувати sort(), limit(), skip()щоб отримати останній N початку запису з будь-якого пропущеного значення

db.collections.find().sort(key:value).limit(int value).skip(some int value);

6

Ви можете спробувати цей метод:

Отримайте загальну кількість записів у колекції за допомогою

db.dbcollection.count() 

Потім скористайтеся пропуском:

db.dbcollection.find().skip(db.dbcollection.count() - 1).pretty()

5

Подивіться під Запит: сортування та природний порядок, http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order , а також сортувати () за курсорами Методи http://www.mongodb.org/display / DOCS / Розширені + Запити


1
Дякуємо за твою враження, це близько, але я хочу переглядати записи, упорядковані від менш останніх до останніх, чи це можливо?
Бен Чен

На природний порядок не слід покладатися; якщо ви використовуєте набір реплік (і вам слід), різні вузли можуть мати однакові документи, збережені в іншому порядку на диску.
Вінс Боудрен

Якщо ви хочете отримати останні записи, вам доведеться покластись на поле дати в документі.
Вінс Боудрен

5

Ви не можете "пропустити" виходячи з розміру колекції, оскільки це не враховує умови запиту.

Правильним рішенням є сортування за потрібною кінцевою точкою, обмеження розміру набору результатів, а потім при необхідності відрегулювати порядок результатів.

Ось приклад, заснований на реальному коді.

var query = collection.find( { conditions } ).sort({$natural : -1}).limit(N);

query.exec(function(err, results) {
    if (err) { 
    }
    else if (results.length == 0) {
    }
    else {
        results.reverse(); // put the results into the desired order
        results.forEach(function(result) {
            // do something with each result
        });
    }
});

Приємного подолання! Було б непогано мати можливість зробити те ж саме на рівні запиту. Щось подібне var query = collection.find( { conditions } ).sort({$natural : -1}).reverse().limit(N).
inwpitrust

4

@ бін-чень,

Ви можете використовувати агрегацію для останніх n записів підмножини документів у колекції. Ось спрощений приклад без групування (що б ви робили між етапами 4 та 5 в цьому випадку).

Це повертає останні 20 записів (на основі поля під назвою "часова мітка"), відсортованого за зростанням. Потім він проектує всі документи _id, часові позначки та що-небудь_field_you_want_to_show у результати.

var pipeline = [
        {
            "$match": { //stage 1: filter out a subset
                "first_field": "needs to have this value",
                "second_field": "needs to be this"
            }
        },
        {
            "$sort": { //stage 2: sort the remainder last-first
                "timestamp": -1
            }
        },
        {
            "$limit": 20 //stage 3: keep only 20 of the descending order subset
        },
        {
            "$sort": {
                "rt": 1 //stage 4: sort back to ascending order
            }
        },
        {
            "$project": { //stage 5: add any fields you want to show in your results
                "_id": 1,
                "timestamp" : 1,
                "whatever_field_you_want_to_show": 1
            }
        }
    ]

yourcollection.aggregate(pipeline, function resultCallBack(err, result) {
  // account for (err)
  // do something with (result)
}

так, результат виглядатиме приблизно так:

{ 
    "_id" : ObjectId("5ac5b878a1deg18asdafb060"),
    "timestamp" : "2018-04-05T05:47:37.045Z",
    "whatever_field_you_want_to_show" : -3.46000003814697
}
{ 
    "_id" : ObjectId("5ac5b878a1de1adsweafb05f"),
    "timestamp" : "2018-04-05T05:47:38.187Z",
    "whatever_field_you_want_to_show" : -4.13000011444092
}

Сподіваюсь, це допомагає.


1
ДЯКУЙТЕ @ lauri108! З усіх відповідей на це та пов’язані з цим питання, це ТІЛЬКИ робоче і надійне рішення "як отримати ОСТАННІ ДОКЛАДИ". І досить просто, щоб зробити це за один запит. Робота виконана.
випадковий носок

@randomsock якщо вам це подобається, проголосуйте за нього :)
lauri108

4

Сортування, пропуск тощо може бути досить повільним, залежно від розміру вашої колекції.

Кращої продуктивності можна було б досягти, якби колекція була проіндексована за деякими критеріями; і тоді ви можете використовувати курсор min ():

По-перше, індексуйте колекцію за допомогою db.collectionName.setIndex( yourIndex ) Ви можете використовувати порядок зростання або спадання, що є крутим, тому що ви завжди хочете "N останніх предметів" ... так що якщо індексувати за низхідним порядком, це те саме, що отримувати "перші N позицій" .

Потім ви знайдете перший елемент колекції та використовуєте значення його індексу в якості мінімальних критеріїв у пошуку, наприклад:

db.collectionName.find().min(minCriteria).hint(yourIndex).limit(N)

Ось посилання на курсор min (): https://docs.mongodb.com/manual/reference/method/cursor.min/


Єдина відповідь, яка враховує ефективність, чудове доповнення :)
zardilior

Чи гарантує ця відповідь порядок?
zardilior

так, гарантує, виходячи з вашого індексу
Жоао Отеро

Мабуть, ви можете просто забути хв і використовувати: db.collectionName.find().hint(yourIndex).limit(N) Якщо індекс знаходиться в порядку зменшення, ви отримуєте N мінімальних значень.
халтукс


0
db.collection.find().hint( { $natural : -1 } ).sort(field: 1/-1).limit(n)

згідно з документацією mongoDB :

Ви можете вказати {$ natural: 1}, щоб змусити запит виконувати сканування колекції вперед.

Ви також можете вказати {$ natural: -1}, щоб змусити запит виконувати зворотне сканування колекції.


0

використовувати оператор $ slice для обмеження елементів масиву

GeoLocation.find({},{name: 1, geolocation:{$slice: -5}})
    .then((result) => {
      res.json(result);
    })
    .catch((err) => {
      res.status(500).json({ success: false, msg: `Something went wrong. ${err}` });
});

де геолокація - це масив даних, ми отримуємо останні 5 записів.


-5

Остання функція повинна бути sort, ні limit.

Приклад:

db.testcollection.find().limit(3).sort({timestamp:-1}); 

2
Це здається неправильним. Чому б sortпісля limit?
Acumenus
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.