在mongodb中搜索嵌入的注释



我想做一个简单的"聊天",那里有一篇帖子和他们的答案(只有1个深度),我决定走这条路,所以一个文档看起来像这个

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

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

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

请注意,在获取结果时,一旦与父级或子级匹配,您将收到包含父级和子级的整个mongo文档。如果您想避免这种情况(以确定您已经找到了什么),您可以首先只对父级运行regex查询,然后只对子级运行regex查询,而不是单个$or查询。

有关$elemMatch的更多详细信息,请访问:docs.mongoodb.org/manual/reference/operator/query/elemMatch

正如前面的注释中所述,"find"的基本查询只是在此处使用$or的一个简单问题,它还对返回true的第一个条件进行短路匹配。这里只有一个数组元素,所以不需要$elemMatch,只需要使用"点表示法",因为不需要多个字段匹配:

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

这个确实匹配了符合这些条件的文档,这就是.find()所做的。然而,你似乎在寻找一个有点"更时髦"的东西,你想在"父"结果和"子"结果之间"辨别"。

这有点超出了.find()的范围,而且这种操作实际上是MongoDB其他操作的领域。不幸的是,当您正在寻找与条件匹配的"字符串的一部分"时,在聚合框架之类的东西中不存在执行类似于$regex操作的"逻辑"操作。如果是这样的话,这将是最好的选择,但没有这样的比较运算符,逻辑比较就是你想要的。这同样适用于基于"文本"的搜索,因为仍然需要区分父代和子代。

这不是最理想的方法,因为它确实涉及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 }
    }
)

基本上,与此输入的查询相同的是,它确实选择了您想要的"文档",而这里真正使用的是"scope",它可以更容易地将正则表达式作为参数传递,而无需每次重写JavaScript代码以包含该值。

这里的逻辑很简单,只针对您正在测试的每个"去规范化"元素,看看正则表达式条件是否与该特定元素匹配。返回的结果是"去规范化"的,并区分匹配的元素是父元素还是子元素。

您可以更进一步,只需将其移动到else,就可以不必检查子代是否匹配。同样,如果你愿意的话,你甚至可以通过某种方式返回"第一个"孩子的匹配。

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

相关内容

  • 没有找到相关文章

最新更新