MongoDB:如何在特定用户评论的项目中查找集合中的最新评论

时间:2013-05-12 18:31:38

标签: mongodb

我有一个关于gocomics评论的MongoDB。示例评论(来自 “db.comments.find()。pretty()”):

 
{ 
        "_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“滦”地带。纪念品是2525923,并且是独一无二的 这个评论。其他字段与此问题无关。

一个人可以在同一条带上发表多条评论。对于 例如,“Chocoloop”可能会在2011-11-25发表评论 “滦”条。后面的评论会有相同的条带,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" 
                } 

这说我至少做了一个评论(也许是几个) pearlsbeforeswine strip日期2007-11-28。在我提出的评论中, 最新的一个(纪念最高的一个)已经有了2462203 (mid =“max id”)。

现在,对于每个结果,我想知道:之后有人发表了评论 我做了最后的评论?

对于上面选择的结果,这意味着:是否有任何评论 2007-11-28的pearlsbeforeswine地带,其名称超过了 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是我的评论[SQLite3版本不包括 “评论员”名称字段])。

注意:我的MongoDB纪念品是字符串,而不是整数。那很糟糕,但我 不要认为这会影响这个问题。

2 个答案:

答案 0 :(得分: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 );

基本上,无论你采用哪种方式,你必须拥有两个{$group}步骤,一个用于查找此特定评论员的最大值,另一个用于该条带的最大值。所以它可能是项目,组,组,展开,适当的匹配项目。希望你明白这一点。

顺便说一句,如果你有一个每个条带的唯一标识符(比如说“comicId”),那么你可以获得一个特定的人更简单评论的漫画列表,然后你就不需要聚合了。只需使用:

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

这将显着减少需要汇总的评论数量。跟踪对话/回复的一种更简单的方法可能是让评论“回复”,但我不确定您是在跟踪线索对话还是直接评论。

答案 1 :(得分:1)

我认为这是一个很好的问题和答案,所以我决定在java中使用Spring Data和MongoDB来解决这个问题。要将Asya的答案转换为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类,我必须创建一个缩小结果的类:

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的最大评论数(或mongo id)为2525925,而评论的ID为2525923。因此,在您发表评论后会有一个后来的评论,因此您需要获取该新评论。您需要以编程方式为其编写逻辑。