2016-05-16 61 views
5

我有收集哪些文檔,如:文件返回最後一個 「真」 值的每個組

{ 
    _id: ObjectId(), 
    user: ObjectId(), 
    studentName: String, 
    createdAt: Date, 
    isAbondoned: boolean 
} 

例子是:

1-

{ 
    "_id" : ObjectId("56cd2d36a489a5b875902f0e"), 
    "user" : ObjectId("56c4cafabd5f92cd78ae49d4"), 
    "studentName" : "Aman", 
    "createdAt" : ISODate("2016-02-24T04:10:30.486+0000"), 
    "isAbandoned" : true 
} 

2 -

{ 
    "_id" : ObjectId("56cd2dcda489a5b875902fcd"), 
    "user" : ObjectId("56c4cafabd5f92cd78ae49d4"), 
    "studentName" : "Aman", 
    "createdAt" : ISODate("2016-02-24T04:13:01.932+0000"), 
    "isAbandoned" : false 
} 

3-

{ 
    "_id" : ObjectId("56cee51503b7cb7b0eda9c4c"), 
    "user" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
    "studentName" : "Rajeev", 
    "createdAt" : ISODate("2016-02-25T11:27:17.281+0000"), 
    "isAbandoned" : true, 
} 

現在我想找到學生的名單,他們的「isAbandoned」是他們最後的「createdAt」文件真實。

對於上面的例子中需要的輸出是:

{ 
    "user" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
    "studentName" : "Rajeev" 
} 

因爲studentName「阿曼」最大(createdAt)是第二文檔和「isAbandoned」是該假。

回答

3

執行此操作的最佳方法是使用聚合框架。您需要通過「用戶」$group您的文檔,並使用$last累加器操作員返回每個用戶的最後一個文檔,但爲此,需要使用$sort彙總管線操作員進行初步分類階段。要對文檔進行排序,您需要同時考慮「createdAt」字段和「用戶」字段。

流水線中的最後一個階段是$match階段,您只選擇「isAbandoned」等於true的最後一個文檔。

db.students.aggregate([ 
    { "$sort": { "user": 1, "createdAt": 1 } }, 
    { "$group": { 
     "_id": "$user", 
     "last": { "$last": "$$ROOT" } 
    }}, 
    { "$match": { "last.isAbandoned": true } } 
]) 

返回是這樣的:

{ 
    "_id" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
    "last" : { 
     "_id" : ObjectId("56cee51503b7cb7b0eda9c4c"), 
     "user" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
     "studentName" : "Rajeev", 
     "createdAt" : ISODate("2016-02-25T11:27:17.281Z"), 
     "isAbandoned" : true 
    } 
} 

要獲得期望的結果,我們需要使用$replaceRoot管道運營商從優化版本3.4開始,以促進嵌入文檔到頂級

{ 
    $replaceRoot: { newRoot: "$last" } 
} 

在舊版本中,您需要使用$project聚合流水線操作來重塑我們的文檔。因此,如果我們擴展我們的管道具有以下階段:

{ 
    "$project": { 
     "_id": "$last._id", 
     "user": "$last.user", 
     "studentName": "$last.studentName", 
     "createdAt": "$last.createdAt", 
     "isAbandoned": "$last.isAbandoned" 
}} 

它產生預期的輸出:

{ 
    "_id" : ObjectId("56cee51503b7cb7b0eda9c4c"), 
    "user" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
    "studentName" : "Rajeev", 
    "createdAt" : ISODate("2016-02-25T11:27:17.281Z"), 
    "isAbandoned" : true 
} 
1

這是一個很好的例子,需要按特定字段(createdAt)對數據進行分組,然後比較結果集匹配條件。

  1. 發現最大的學生證,
  2. 比賽只有最大項條目= createdAt
  3. 檢查它們是否合格的標準
  4. 重塑文件

代碼

db.student.aggregate([{ 
    $group : { 
     _id : "$user", 
     created : { 
      $max : "$createdAt" 
     }, 
     documents : { 
      $push : "$$ROOT" 
     } 
    } 
}, { 
$project : { 
    _id : 0, 
    documents : { 
     $filter : { 
     input : "$documents", 
     as : "item", 
      cond : { 
       $eq : ["$$item.createdAt", "$created"] 
      } 
     } 
    }} 
}, { 
$match : { 
    "documents.isAbandoned" : true 
}}, 
{ $unwind : "$documents" }, 
{ 
$project : { 
    _id : "$documents._id", 
    user : "$documents.user", 
    studentName : "$documents.studentName", 
    createdAt : "$documents.createdAt", 
    isAbandoned : "$documents.isAbandoned", 
}} 
]) 
+0

這工作,但確實非常沒有效率的,你真的不需要去通過所有這個麻煩。 – styvane

+0

如果OP使用的是舊的MongoDB版本,因爲'$ filter'是3.2版中的新版本 – styvane

+1

@ user3100115 - db版本沒有指定:-),所以你的代碼將失敗,所以我的假設,btw很好的清潔解決方案! – profesor79

相關問題