查询MongoDB仅返回具有匹配条件的单值文档
如果MongoDB在数组中正好有一个元素与条件匹配,我希望它返回整个文档。我写了以下内容:查询MongoDB仅返回具有匹配条件的单值文档,mongodb,Mongodb,如果MongoDB在数组中正好有一个元素与条件匹配,我希望它返回整个文档。我写了以下内容: db.myCollection.find({ $where: "this.Tags.filter(x => x.indexOf(':') < 0).length === 1" }) db.myCollection.find({$where:“this.Tags.filter(x=>x.indexOf(':'))
db.myCollection.find({ $where: "this.Tags.filter(x => x.indexOf(':') < 0).length === 1" })
db.myCollection.find({$where:“this.Tags.filter(x=>x.indexOf(':'))<0.length==1“})
它工作得很好,只是速度非常慢,因为$where
子句不使用标记
是否可以以某种方式将此查询重写为正常的
查找
/匹配
/..
操作,该操作可以识别标记,或者这是执行此类操作的唯一方法?我可以防御性地添加一些不包含分号的字段,如numberoftags,但我的问题是关于更通用的方法,它不需要更改数据的插入方式。经过几个小时的谷歌搜索和堆栈溢出,我编写了以下解决方案:
db.myCollection.aggregate([
{ $match : { "Tags": ":image" } },
{ $unwind : "$Tags" },
{ $match : { "Tags": /^[^:]+$/ } },
{ $group : { _id : "$_id", doc: { "$first": "$$ROOT" }, count: { $sum : 1} }} ,
{ $match : { "count": 1 } },
{ $replaceRoot : {newRoot: "$doc"} },
{ $addFields : { Tags : [ "$Tags" ] } } // we unwinded all tags, so we convert this field back to an array, otherwise we can get type error
])
它比原始代码快10倍:在我的机器上是3秒,而不是31秒
样本输入
{
"_id" : ObjectId("53396223ec8bd02674b1208c"),
"UploadDate" : ISODate("2014-03-31T12:40:03.834Z"),
"Tags" : [
"cars",
" car_diler",
" autodiler",
" auto",
" audi",
":image"
]
},
{
"_id" : ObjectId("53396223ec8bd02674b1208d"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
":image"
]
},
{
"_id" : ObjectId("53396223ec8bd02674b1208e"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"cars",
":image"
]
},
{
"_id" : ObjectId("53396223ec8bd02674b1208f"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"something",
":image",
":somethingelse"
]
},
{
"_id" : ObjectId("53396223ec8bd02674b120ff"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"something",
":somethingelse"
]
}
电流输出:
{
"_id" : ObjectId("53396223ec8bd02674b1208e"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"cars"
]
},
{
"_id" : ObjectId("53396223ec8bd02674b1208f"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"something"
]
}
期望输出:
{
"_id" : ObjectId("53396223ec8bd02674b1208e"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"cars",
":image"
]
},
{
"_id" : ObjectId("53396223ec8bd02674b1208f"),
"UploadDate" : ISODate("2014-03-31T12:40:03.835Z"),
"Tags" : [
"something",
":image",
":somethingelse"
]
}
如您所见,我在这里松开了所有以:
开头的标记。这对我来说已经足够好了,但对其他人来说可能很重要。我可以先收集ID
,然后查询它们,但在一次查询中执行所有操作是至关重要的。这里有一个更简洁的版本,不需要任何展开
:
db.myCollection.aggregate([
{
$addFields: { // we want to add new field...
"NumberOfTagsWithoutSemiColon": {
$size: { // ...that shall contain the number...
$filter: {
input: "$Tags", // ...of all tags...
cond: {
$eq: // ...that do not contain a semicolon
[
{ $indexOfBytes: [ "$$this", ":" ] },
-1
]
}
}
}
}
}
}, {
$match: {
"NumberOfTagsWithoutSemiColon": 1 // we only keep the ones where
}
}, {
$project: {
"NumberOfTagsWithoutSemiColon": 0
}
}])
如果你发布一些示例数据(用于输入和所需输出),可能会出现更快的解决方案…@dnickless我认为我的问题已经足够清楚了,但我已经在帖子中添加了其他信息。谢谢你的建议。太棒了。您首先忘记了匹配:image
,但这并不影响整个想法。我在您的解决方案中看到了这一点。根据您的描述,$match
阶段不是必需的。它也不包括在基于$where
的版本中。很好。这是一个有点不恰当的问题。但是,我要感谢:)