我想做一个简单的聊天"哪里有帖子和答案(只有1个深),我决定走this方式,所以单个文件看起来像这样
{
_id: ObjectId(...),
posted: date,
author: "name",
content: "content",
comments: [
{ posted: date,
author: "name2"},
content: '...'
}, ... ]
}
我的问题是如何以这种方式搜索内容?我首先需要在"父母"中寻找匹配。内容,然后是评论列表中的内容。我该怎么做?
答案 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
即可。以同样的方式你甚至可以返回"第一个"如果那是你的愿望,那么通过某种方式与孩子进行比赛。
无论如何,这应该让你在最终代码看起来的路径上。但这是在服务器上处理这种区别的唯一方法的基本方法,客户端后处理将遵循相同的模式。