2013-05-12 47 views
1

我有GoComics等評論的MongoDB的。樣本評論(從 「db.comments.find()漂亮的()。」):MongoDB的:如何找到收集項目最新評論特定用戶評論

 
{ 
     "_id" : ObjectId("518f14e5394594efbe18068c"), 
     "body" : "plan for it", 
     "commentid" : "2525923", 
     "commentor" : "Chocoloop", 
     "commentorid" : "769338", 
     "da" : "25", 
     "filename" : "/mnt/sshfs/gocomics/comments/100.out.bz2", 
     "mo" : "11", 
     "strip" : "luann", 
     "stripname" : "Luann", 
     "time" : "1 day ago", 
     "yy" : "2011" 
} 

這表明, 「Chocoloop」 關於 2011-11-提出的意見 「計劃,它」 25「Luann」條。該紀念品是2525923,並且是 此評論獨有的。其他字段與此問題無關。

單人可以在同一條多條評論。對於 例如,「Chocoloop」 may've就這一2011-11-25 「Luann」條以後的評論。後面的評論會有相同的地帶,da,mo, 年,評論者字段,但更高的紀念。

我想找到我的每個條作出的最新評論。這很容易:

 
db.comments.aggregate( 
{$match: {commentor:"barrycarter"}}, 
{$group: {_id: {strip: "$strip", yy: "$yy", da:"$da", mo:"$mo"}, 
mid: {$max:"$commentid"}}} 
) 

這裏是衆多成果之一:

 
       { 
         "_id" : { 
           "strip" : "pearlsbeforeswine", 
           "yy" : "2007", 
           "da" : "28", 
           "mo" : "11" 
         }, 
         "mid" : "2462203" 
       } 

這是說我做了2007-11日在 pearlsbeforeswine帶至少一個註釋(也許還有好幾個) -28。我提出的意見,將 最新的一個(具有最高commentid)已經commentid 2462203 (MID =「最大ID」)。現在

,對於每個結果,我想知道:已經有人做 後評論我做了我最後的評論?

對於上面的選定結果,這意味着:有沒有關於 日期2007-11-28,其紀念超過 2462203?

當然,我可以寫一個特殊情況的查詢:


db.comments.find( 
{strip:"pearlsbeforeswine",yy:"2007",da:"28",mo:"11", 
commentid: {$gt: "2462203"}} 
).pretty() 

,但我怎麼做它在結果集中的所有結果,而不 爲每一個創建一個單獨的查詢(甚至自動,這看起來好像是醜陋的)。

這是一個貧窮的用例MongoDB的?我有一個類似的(不相同) sqlite3的數據庫,在那裏這個查詢:


SELECT * FROM (SELECT strip,month,date,year,MAX(id) AS mid FROM 
comments WHERE commentorid=801127 GROUP BY strip,month,date,year) AS t 
JOIN comments c ON (t.strip=c.strip AND t.month=c.month AND 
t.date=c.date AND t.year=c.year AND c.id > t.mid) 

(其中801127是我commentorid [SQLite3的該版本不包括 「評註」名稱字段])。

注:我的MongoDB commentid的是字符串,而不是整數。這是不好的,但我 不認爲它影響這個問題。

+0

您沒有註釋中特定條的唯一標識符?只是帶yy-mo-da的組合? (我猜文件名是一個唯一的標識符,但它似乎hacky)... – 2013-05-12 19:27:14

+0

不,我不知道,但我想我可以創建一個(文件名不唯一,每個文件名有20個評論)。 MongoDB的多字段索引是否有問題?會創建一個「strip-yy-mo-da」字段幫助嗎?我假設MongoDB沒有意見和/或創建「strip-yy-mo-da」作爲虛擬字段不會有幫助? – barrycarter 2013-05-12 19:33:14

+0

看到我的答案 - 第一個項目階段只是將名稱合併到唯一的條形標識符中,主要是爲了進一步簡化語法。只是想知道沒有帶yy-mm-dd類型的場的原因是什麼。並不一定是唯一的 - 對這些類型的模式來說,分箱是一個很好的答案。 – 2013-05-12 20:16:29

回答

2

你可以使用聚合框架來實現它,並且有多種方法可以實現這一點。最簡單的是有點蠻力和長 - 它可能不會有最好的表現,但我認爲這是最簡單的理解:

proj={"$project": { 
     "strip" : {"$concat" : ["$strip","-","$yy","/","$mo","/","$da"]}, 
    "commentor" : 1, 
    "commentid" : 1 
    } 
}; 

group={"$group": { 
    "_id" : "$strip", 
    "comms" : { 
     "$push" : { 
      "c" : "$commentor", 
      "i" : "$commentid" 
     } 
    }, 
    "max" : { 
     "$max" : "$commentid" 
    } 
}}; 

match = { "$match" : { "comms.c" : "<commentorname>" } }; 
unwind = { "$unwind" : "$comms" }; 

proj2 = { "$project" : { 
     "meLast" : {"$cond" : [ 
      {"$eq" : [ 
        "$max", 
        "$comms.i" 
       ] 
      }, 
      1, 
      0 
     ] } 
    } 
}; 
group2 = {"$group" : { 
"_id" : "$_id", 
"afterMe" : { 
    "$max" : "$meLast" 
} 
} }; 

match2 = { "$match" : { "afterMe" : 0 } }; 

db.comments.aggregate(proj, group, match, unwind, match, proj2, group2, match2); 

基本上,你做的任何一個方式,也有在管道2層{$group}的步驟,你必須有一個可以找到這個特定評論者的最高紀錄,以及一個超過該紀錄片的紀錄。因此,它可能是項目,小組,團隊,放鬆,適當的項目與比賽。希望你明白這個主意。順便說一句,如果你有每個帶的唯一標識符(比如說「comicId」),那麼你就可以得到一個特定人評論的漫畫列表要簡單得多,然後你就不需要聚合那麼多了可以使用:

db.comments.distinct("comicId",{commentor:"name"}) 

這將顯着減少需要聚合的評論數量。跟蹤對話/回覆的簡單方法可能是讓評論有「回覆」,但是我不確定您是跟蹤線索對話還是直接評論。

+0

謝謝。實際上,我最終添加了索引並讓我的SQLite3數據庫執行此操作。 1)SQLite3對於這個查詢太慢了,並且2)希望爲只讀數據庫找到更好的解決方案。 – barrycarter 2013-05-16 19:53:35

1

我認爲這是一個很好的問題和答案,所以我決定在Java中使用Spring Data與MongoDB解決此問題。要阿霞的回答轉換成Java mongodb的代碼,我做了以下內容:

public void commentTest() { 

    BasicDBObject o1 = new BasicDBObject(); 
    o1.append("c", "$commentor"); 
    o1.append("i", "$commentid"); 
    Aggregation aggCount = newAggregation(
      project("commentid", "commentor") 
        .andExpression("concat(\"$strip\",\"-\",\"$yy\",\"/\",\"$mo\",\"/\",\"$da\")").as("strip"), 
      group("strip").push(o1).as("comms").max("commentid").as("max"), 
      match(Criteria.where("comms.c").is("Simon")), 
      unwind("comms"), 
      match(Criteria.where("comms.c").is("Simon"))); 
    logger.info(aggCount.toString()); 
    AggregationResults<CommentTest> groupCount = mongoTemplate.aggregate(aggCount, "commenttest", CommentTest.class); 
    List<CommentTest> resultCount = groupCount.getMappedResults(); 

    ObjectMapper mapper = new ObjectMapper(); 
    try { 
     logger.info(mapper.writeValueAsString(resultCount)); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

然後讓mongotemplate成功解析結果爲CommentTest類,我不得不創建minicks結果類:

Document(collection = "commenttest") 
@JsonInclude(JsonInclude.Include.NON_NULL) 
public class CommentTest { 

    private String id, body, commentid, commentor, commentorid, da, filename, mo, strip, stripname, time, yy, max; 
    @JsonProperty 
    private comms comms; 

    public CommentTest.comms getComms() { 
     return comms; 
    } 

    public void setComms(CommentTest.comms comms) { 
     this.comms = comms; 
    } 

    public static class comms implements Serializable { 
     private String c,i; 

     public String getC() { 
      return c; 
     } 

     public void setC(String c) { 
      this.c = c; 
     } 

     public String getI() { 
      return i; 
     } 

     public void setI(String i) { 
      this.i = i; 
     } 
    } 

    public String getId() { 
     return id; 
    } 

    public void setId(String id) { 
     this.id = id; 
    } 

    public String getBody() { 
     return body; 
    } 

    public void setBody(String body) { 
     this.body = body; 
    } 

    public String getCommentid() { 
     return commentid; 
    } 

    public void setCommentid(String commentid) { 
     this.commentid = commentid; 
    } 

    public String getCommentor() { 
     return commentor; 
    } 

    public void setCommentor(String commentor) { 
     this.commentor = commentor; 
    } 

    public String getCommentorid() { 
     return commentorid; 
    } 

    public void setCommentorid(String commentorid) { 
     this.commentorid = commentorid; 
    } 

    public String getDa() { 
     return da; 
    } 

    public void setDa(String da) { 
     this.da = da; 
    } 

    public String getFilename() { 
     return filename; 
    } 

    public void setFilename(String filename) { 
     this.filename = filename; 
    } 

    public String getMo() { 
     return mo; 
    } 

    public void setMo(String mo) { 
     this.mo = mo; 
    } 

    public String getStrip() { 
     return strip; 
    } 

    public void setStrip(String strip) { 
     this.strip = strip; 
    } 

    public String getStripname() { 
     return stripname; 
    } 

    public void setStripname(String stripname) { 
     this.stripname = stripname; 
    } 

    public String getTime() { 
     return time; 
    } 

    public void setTime(String time) { 
     this.time = time; 
    } 

    public String getYy() { 
     return yy; 
    } 

    public void setYy(String yy) { 
     this.yy = yy; 
    } 

    public String getMax() { 
     return max; 
    } 

    public void setMax(String max) { 
     this.max = max; 
    } 
} 

我然後通過插入這些4個模擬條目創建MongoDB中一些測試數據:

{ "_id" : ObjectId("518f14e5394594efbe18068c"), "body" : "1", "commentid" : "2525923", "commentor" : "Simon", "commentorid" : "769338", "da" : "25", "filename" : "/mnt/sshfs/gocomics/comments/100.out.bz2", "mo" : "11", "strip" : "luann", "stripname" : "Luann", "time" : "1 day ago", "yy" : "2011" } 
{ "_id" : ObjectId("518f14e5394594efbe18068d"), "body" : "2", "commentid" : "2525924", "commentor" : "Josh", "commentorid" : "769339", "da" : "25", "filename" : "/mnt/sshfs/gocomics/comments/100.out.bz2", "mo" : "11", "strip" : "luann", "stripname" : "Luann", "time" : "1 day ago", "yy" : "2011" } 
{ "_id" : ObjectId("518f14e5394594efbe18068e"), "body" : "3", "commentid" : "2525925", "commentor" : "Peter", "commentorid" : "769340", "da" : "25", "filename" : "/mnt/sshfs/gocomics/comments/100.out.bz2", "mo" : "11", "strip" : "luann", "stripname" : "Luann", "time" : "1 day ago", "yy" : "2011" } 
{ "_id" : ObjectId("518f14e5394594efbe18068f"), "body" : "old1", "commentid" : "2525905", "commentor" : "Peter", "commentorid" : "769340", "da" : "24", "filename" : "/mnt/sshfs/gocomics/comments/100.out.bz2", "mo" : "11", "strip" : "luann", "stripname" : "Luann", "time" : "1 day ago", "yy" : "2011" } 

我然後跑的代碼和這裏的結果:

[{"id":"luann-2011/11/25","max":"2525925","comms":{"c":"Simon","i":"2525923"}}] 

結果可以解釋爲後luann-2011/11/25具有最大評論數(或蒙戈ID)爲2525925,而您的評論有2525923的ID。因此,您有評論後有評論,因此您需要獲取新的評論。你需要編寫你的邏輯編程。