查询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(':'))

如果MongoDB在数组中正好有一个元素与条件匹配,我希望它返回整个文档。我写了以下内容:

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
的版本中。很好。这是一个有点不恰当的问题。但是,我要感谢:)