วิธีรับ N ระเบียนสุดท้ายใน MongoDB?


523

ฉันไม่พบที่ใดก็ได้ที่มีเอกสารนี้ โดยค่าเริ่มต้นการดำเนินการค้นหา () จะได้รับบันทึกตั้งแต่ต้น ฉันจะได้รับการบันทึก N ครั้งล่าสุดใน mongodb ได้อย่างไร?

แก้ไข: ฉันต้องการผลลัพธ์ที่ส่งคืนซึ่งเรียงลำดับจากน้อยไปมากล่าสุดไม่ใช่ย้อนกลับ


7
@ ฮาอิมโปรดระบุคำตอบเฉพาะส่วนใดของหน้าเว็บที่ช่วยแก้ไขคำถามของฉัน
Bin Chen

สวัสดี @BinChen ฉันมีปัญหาเดียวกันเมื่อเร็ว ๆ นี้มันแก้ไขได้หรือไม่
Hanton

คำตอบ:


736

หากฉันเข้าใจคำถามของคุณคุณต้องเรียงลำดับจากน้อยไปมาก

สมมติว่าคุณมี ID หรือเขตข้อมูลวันที่เรียกว่า "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ขึ้นอยู่กับลำดับที่คุณต้องการ

ใช้. จำกัด ()


สุดท้ายเป็นแนวปฏิบัติที่ดีที่จะเพิ่มขีด จำกัด เมื่อทำคิวรีเปิดกว้างประเภทนี้เพื่อให้คุณสามารถทำได้ ...

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

หรือ

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

11
@MortezaM ฉันค่อนข้างแน่ใจว่าคุณมีคำสั่งแบบสอบถามของคุณผสม ... การเรียงลำดับของคุณ () ควรจะใช้งานได้ไม่ใช่ลำดับแรก (เหมือนกับ SQL ORDER BY) .find ({}) ข้าม (1) .limit ( 50) .sort ({"date": - 1})
Justin Jenkins

6
ลำดับของการเรียกใช้ฟังก์ชันไม่ควรเกี่ยวข้องกับผลลัพธ์สุดท้าย
Morteza Milani

7
@MortezaM แน่นอนว่าคำสั่งนั้นสำคัญ item = 3; item.add(3).divide(3) == 2; item.divide(3).add(3) == 4;โดยไม่มีคำสั่งสิ่งที่จะเป็นผล? ฉันเห็นด้วยกับคุณว่าคำสั่งซื้อที่กลับรายการนี้ไม่ง่าย นี่ไม่ใช่ SQL หลังจากทั้งหมดควรเป็นไปตามกระบวนทัศน์ OO ปกติ
RickyA

38
แต่คำสั่งก็ไม่สำคัญ สิ่งที่คุณต้องทำคือลองดูว่ามันไม่ได้ สิ่งเหล่านี้ถูกเรียกบนเคอร์เซอร์และส่งผ่านไปยังเซิร์ฟเวอร์ดังนั้นเซิร์ฟเวอร์จึง จำกัด ผลลัพธ์ของการเรียงลำดับ (บนสุด) เนื่องจากไม่มีสิ่งใดที่เหมาะสม
Asya Kamsky

10
เอกสารยืนยันว่าการสั่งซื้อไม่สำคัญ: ลิงก์
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);
}

แล้วจากเปลือก Mongo เพียงแค่พิมพ์ last(N)


1
db.collection.find().reverse().limit(1)ทำให้ฉันมีข้อผิดพลาด... has no method reverse
Catfish

@ แคทฟิชคุณพูดถูกฉันเพิ่งสังเกตเห็นว่า reverse () ถูกเพิ่มโดย [Mongo-Hacker] ( tylerbrock.github.com/mongo-hacker ) ฉันจะอัปเดตคำตอบของฉัน ขอบคุณ
Trasplazio Garzuglio

1
db.getCollection ('COLLECTION_NAME'). find (). ข้าม (db.getCollection ('COLLECTION_NAME'). count () - N) ใช้งานได้ดีสำหรับฉัน :)
Spl2nky

นี่ควรเป็นคำตอบของคำถามไม่ใช่คำตอบของ Justin Jenkins
Jadiel de Armas

ระเบียบธรรมชาติไม่ควรพึ่งพา หากคุณกำลังใช้ชุดเรพพลิกา (และคุณควรจะเป็น) โหนดที่ต่างกันอาจมีเอกสารเดียวกันอยู่ในลำดับที่แตกต่างกันบนดิสก์
Vince Bowdren

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 ล่าสุดหายไปในคำตอบ
Ajay

ระเบียบธรรมชาติไม่ควรพึ่งพา หากคุณกำลังใช้ชุดเรพพลิกา (และคุณควรจะเป็น) โหนดที่ต่างกันอาจมีเอกสารเดียวกันอยู่ในลำดับที่แตกต่างกันบนดิสก์
Vince Bowdren

6

คุณสามารถใช้sort(), limit(), skip()ที่จะได้รับที่ผ่านมายังไม่มีการบันทึกเริ่มต้นจากมูลค่าข้ามใด ๆ

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 / เอกสาร / ขั้นสูง + แบบสอบถาม


1
ขอบคุณสำหรับ anwser ของคุณมันอยู่ใกล้ แต่ฉันต้องการที่จะรักษาระเบียนที่เรียงลำดับจากน้อยไปหาล่าสุดเป็นไปได้ไหม?
Bin Chen

ระเบียบธรรมชาติไม่ควรพึ่งพา หากคุณกำลังใช้ชุดเรพพลิกา (และคุณควรจะเป็น) โหนดที่ต่างกันอาจมีเอกสารเดียวกันอยู่ในลำดับที่แตกต่างกันบนดิสก์
Vince Bowdren

หากคุณต้องการได้รับบันทึกล่าสุดคุณจะต้องพึ่งพาฟิลด์วันที่ในเอกสาร
Vince Bowdren

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

@ bin-chen,

คุณสามารถใช้การรวมสำหรับรายการล่าสุดของชุดย่อยของเอกสารในคอลเลกชัน ต่อไปนี้เป็นตัวอย่างแบบง่าย ๆ โดยไม่จัดกลุ่ม (ซึ่งคุณจะทำระหว่างขั้นตอนที่ 4 ถึง 5 ในกรณีนี้)

ส่งคืน 20 รายการล่าสุด (ขึ้นอยู่กับเขตข้อมูลที่เรียกว่า "timestamp") เรียงลำดับจากน้อยไปมาก จากนั้นจะฉายแต่ละเอกสาร _id, การประทับเวลาและอะไรก็ตามที่ _ ฟิลด์ _ คุณ _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! จากคำตอบทั้งหมดสำหรับคำถามนี้และคำถามที่เกี่ยวข้องนี่เป็นทางออกเดียวที่เชื่อถือได้สำหรับ "วิธีการรับ LAST N DOCS" และง่ายพอที่จะทำในหนึ่งแบบสอบถาม งานเสร็จแล้ว
randomsock

@randomsock ถ้าคุณชอบมันออกเสียงลงคะแนนมันขึ้น :)
lauri108

4

การเรียงลำดับการข้ามและอื่น ๆ อาจค่อนข้างช้าขึ้นอยู่กับขนาดของคอลเลกชันของคุณ

ประสิทธิภาพที่ดีขึ้นจะเกิดขึ้นได้หากคุณมีการจัดทำดัชนีคอลเลกชันของคุณตามเกณฑ์บางประการ และจากนั้นคุณสามารถใช้เคอร์เซอร์ min ():

ขั้นแรกให้ทำดัชนีคอลเล็กชันของคุณด้วยdb.collectionName.setIndex( yourIndex ) คุณสามารถใช้ลำดับจากน้อยไปมากหรือมากไปหาน้อยซึ่งเท่เพราะคุณต้องการ "N รายการสุดท้าย" เสมอ ... ดังนั้นถ้าคุณทำดัชนีโดยเรียงจากมากไปน้อยมันก็เหมือนกับการได้รับ "รายการแรก" .

จากนั้นคุณจะพบรายการแรกของคอลเล็กชันของคุณและใช้ค่าฟิลด์ดัชนีเป็นเกณฑ์ขั้นต่ำในการค้นหาเช่น:

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

นี่คือข้อมูลอ้างอิงสำหรับเคอร์เซอร์ min (): https://docs.mongodb.com/manual/reference/method/cursor.min/


เฉพาะคำตอบที่คำนึงถึงประสิทธิภาพเท่านั้นนอกจากนี้ยังมีอีกมาก :)
zardilior

คำตอบนี้รับประกันการสั่งซื้อหรือไม่
zardilior

ใช่มันรับประกันตามดัชนีของคุณ
João Otero

1
เห็นได้ชัดว่าคุณสามารถลืมนาทีและใช้: db.collectionName.find().hint(yourIndex).limit(N) หากดัชนีอยู่ในลำดับถัดลงมาคุณจะได้รับค่าต่ำสุด N
haltux


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

ฟังก์ชั่นล่าสุดที่ควรจะเป็นไม่ได้sortlimit

ตัวอย่าง:

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

2
ดูเหมือนว่าไม่ถูกต้อง ทำไมจะsortอยู่หลังlimit?
คิวเมนตัส
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.