[英]Get last documents with a distinct criteria
我無法想出一個很好的方法來進行某個MongoDb查詢。 首先,這是我想要做什么樣的查詢。 假設一個簡單的數據庫通過電子卡刷卡記錄進入和退出事件(可能還有其他操作,無關緊要)。 所以有一個名為swipelog
的集合,其中包含如下所示的簡單文檔:
{
_id: ObjectId("524ab4790a4c0e402200052c")
name: "John Doe",
action: "entry",
timestamp: ISODate("2013-10-01T1:32:12.112Z")
}
現在我想列出名稱及其最后輸入時間(以及我可能想要的任何其他字段,但下面的示例僅使用這兩個字段)。
以下是我現在所擁有的,作為MongoDb JavaScript控制台的“一線”:
db.swipelog.distinct('name')
.forEach( function(name) {
db.swipelog.find( { name: name, action:"entry" } )
.sort( { $natural:-1 } )
.limit(1)
.forEach( function(entry) {
printjson( [ entry.name, entry.timestamp ] )
})
})
其中印有以下內容:
[ "John Doe", ISODate("2013-10-01T1:32:12.112Z")]
[ "Jane Deo", ISODate("2013-10-01T1:36:12.112Z")]
...
我認為上面有明顯的縮放問題。 如果有一百個名稱,那么將對數據庫進行1 + 100次查詢。 那么獲得“每個不同name
最后timestamp
”的好/正確方法是什么? 如果更容易,更改數據庫結構或添加一些集合是可以的。
您可以使用聚合框架來實現此目的:
db.collection.aggregate(
[
{$match:
{action:'entry'}
},
{$group:
{_id:'$name',
first:
{$max:'$timestamp'}
}
}
])
如果您可能在結果中包含其他字段,則可以使用$ first運算符
db.collection.aggregate(
[
{$match:
{action:'entry'}
},
{$sort:
{name:1, timestamp:-1}
},
{$group:
{_id:'$name',
timestamp: {$first:'$timestamp'},
otherField: {$first:'$otherField'},
}
}
])
這個答案應該是對attish上面的回答的評論,但我沒有足夠的代表來評論
請記住,聚合框架不能返回超過16MB的數據 。 如果您擁有大量用戶,則可能會在生產系統上遇到此限制。
MongoDB 2.6為聚合框架添加了新功能來處理這個問題:
db.collection.aggregateCursor()
(臨時名稱)與db.collection.aggregate()
完全相同,只是它返回游標而不是文檔。 這避免了16MB的限制 $out
是一個新的管道階段,它將管道的輸出定向到一個集合。 這允許您運行聚合作業 $sort
已得到改進,以消除其RAM限制並提高速度 如果查詢性能比數據時代更重要,您可以安排一個常規aggregate
命令,將其結果存儲在集合中,如db.last_swipe
,然后讓您的應用程序只查詢相關用戶的db.last_swipe
。
結論:我同意attish有正確的方法。 但是,您可能在當前的MongoDB版本上縮放它時遇到麻煩,應該查看Mongo 2.6。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.