在mongodb中搜索嵌入式注释

时间:2014-09-02 21:23:13

标签: javascript mongodb mapreduce mongodb-query

我想做一个简单的聊天"哪里有帖子和答案(只有1个深),我决定走this方式,所以单个文件看起来像这样

{
    _id: ObjectId(...),
    posted: date,
    author: "name",
    content: "content",
    comments: [
        { posted: date,
          author:  "name2"},
          content: '...' 
        }, ... ]
}

我的问题是如何以这种方式搜索内容?我首先需要在"父母"中寻找匹配。内容,然后是评论列表中的内容。我该怎么做?

2 个答案:

答案 0 :(得分:2)

如果您可以在每个内容中搜索正则表达式,则可以使用: {$or : [ {'content':{$regex:'your search regex'}}, {'comments' : { $elemMatch: { 'content':{$regex:'your search regex'}}}]}

请注意,在获取结果时,在与父母或孩子匹配时,您将收到包含父母和孩子的整个mongo文档。 如果你想避免这种情况(为了确定你发现了什么),你可以先在父项上运行一个正则表达式查询,然后再在子项上运行,而不是单个$or查询。

有关$elemMatch的详细信息,请查看:docs.mongodb.org/manual/reference/operator/query/elemMatch

答案 1 :(得分:1)

如前面评论中所述,基本查询"找到"这里使用$or只是一个简单的问题,它也会在返回true的第一个条件下进行短路匹配。这里只有一个数组元素,因此不需要$elemMatch,但只需使用"点符号"因为不需要多个字段匹配:

db.messages.find({
    "$or": [
        { "content": { "$regex": ".*Makefile.*" } },
        { "comments.content": { "$regex": ".*Makefile.*" } }
    ]
})

这个 实际上匹配符合这些条件的文档,这就是.find()的作用。然而,你似乎正在寻找的东西有点" funkier" 你想要"辨别"在父母之间"结果和一个孩子"结果

这有点超出.find()的范围,并且这种操作实际上是MongoDB的其他操作的域。不幸的是,因为你正在寻找"字符串的一部分"作为你的条件匹配,做一个"逻辑"在聚合框架之类的东西中不存在等效的$regex操作。如果它确实是最好的选择,但是没有这样的comparison operator,逻辑比较就是你想要的。这同样适用于" text"基于搜索,因为仍然需要从孩子身上辨别父母。

不是最理想的方法,因为它确实涉及JavaScript处理,但这里的下一个最佳选择是mapReduce()

db.messages.mapReduce(
    function() {
        // Check parent
        if ( this.content.match(re) != null )
            emit(
                { "_id": this._id, "type": "P", "index": 0 },
                { 
                    "posted": this.posted, 
                    "author": this.author, 
                    "content": this.content
                }
            );

        var parent = this._id;
        // Check children
        this.comments.forEach(function(comment,index) {
          if ( comment.content.match(re) != null )
              emit(
                  { "_id": parent, "type": "C", "index": index },
                  {
                      "posted": comment.posted, 
                      "author": comment.author, 
                      "content": comment.content
                  }
              );
        });
    },
    function() {},  // no reduce as all are unique
    {
        "query": {
            "$or": [
                { "content": { "$regex": ".*Makefile.*" } },
                { "comments.content": { "$regex": ".*Makefile.*" } }
            ]
        },
        "scope": { "re": /.*Makefile.*/ },
        "out": { "inline": 1 }
    }
)

基本上输入相同的查询会选择"文件"你想要并且真的只是使用"范围"这样就可以更容易地将正则表达式作为参数传递,而无需重新编写JavaScript代码以便每次都包含该值。

逻辑很简单,只是对每个"去标准化"您正在测试的元素,以查看正则表达式条件是否与该特定元素匹配。结果返回"去标准化"并辨别匹配的元素是父母还是孩子。

你可以采取进一步的措施而不用费心去检查孩子是否匹配,只需将其移至else即可。以同样的方式你甚至可以返回"第一个"如果那是你的愿望,那么通过某种方式与孩子进行比赛。

无论如何,这应该让你在最终代码看起来的路径上。但这是在服务器上处理这种区别的唯一方法的基本方法,客户端后处理将遵循相同的模式。