【问题标题】:mongodb $where query to fetch sub-document contentmongodb $where 查询获取子文档内容
【发布时间】:2017-06-26 20:09:07
【问题描述】:

以下 mongodb 查询未返回文档。查询有什么问题?我想指定$where 来匹配数组中的一个元素

[EDIT] 以上问题是我的场景的简化版本。我正在使用 spring 数据 mongodb 存储库。我想使用 @Query 注释指定查询。希望$where 部分是简单的比较,而不是完整的 javascript 函数。像

@Query ( value=" { flag: true, $where: \"this.versions.version == this.defaultVersion \"}", fields = "{'versions' : 1}" )
Foo getDefaultVersion();

如果$where 的语法不正确,请提出替代方案。

db.foo.find({
    flag: true,
    $where: "this.versions.version == this.defaultVersion " },
    { 'versions' : 1}
});

收藏:

{
    flag: true,
    defaultVersion: "1.0",
    versions: [
        {
            version: "1.0",
            tags: ["abc", "def"]
        },
        {
            version: "1.1",
            tags: ["abc", "def"]
        }
    ]
}

我想从具有匹配版本作为 defaultVersion 属性的版本数组中获取“版本”子文档。

[EDIT2]我能够使用 $elemMatch 缩小范围

db.foo.find({
    flag: true,
    versions: { $elemMatch : { version: '1.0' } } 
    },
    { 'versions' : 1}
});

在上面的硬编码'1.0' 的地方,我想指定文档的defaultVersion。不知道如何实现?

【问题讨论】:

  • 你的版本是数组,this.versions.version会给你未定义的,如果你只想匹配第一个位置,尝试使用this.versions[0].version @Jack
  • 我不知道在版本上使用索引的前期位置。我希望查询遍历所有版本并将版本与 defaultVersion 匹配。不知道如何为此编写查询。有什么建议吗?

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

在大多数情况下应避免使用 $where 运算符,因为无论其他什么条件可能使用索引选择,它都会调用完整的集合扫描。

此外,您正在对每个结果文档调用 JavaScript 解释器,这将比本机代码慢得多。阅读手册页上的警告,它们的存在是有原因的

请尽可能使用.aggregate() 进行此类比较。在您的情况下,这绝对是更好的选择:

db.foo.aggregate([
    { "$match": { "flag": true } },
    { "$unwind": "$versions" },
    { "$project": {
        "versions": "$versions"
        "same": { "$eq": [ "$versions.version", "$defaultVersion" ] }
    }}
    { "$match": { "same": true } },
    { "$project": {
        "_id": 0,
        "versions": 1
    }}
])

这允许您首先通过“标志”条件过滤查询,然后检查数组的每个成员以比较两个字段是否相同。

如有必要,您可以将匹配的数组元素回滚到一个有多个匹配项的数组中。但我认为这不是你的要求。

【讨论】:

  • 查询效果很好。我将使用它的 spring-data 等价物
【解决方案2】:

试试这个:

db.so.find({
    flag: true,
    $where: function () {
        var versions = this.versions; 
        for (var i=0; i<versions.length; i++) {
            if (versions[i].version == this.defaultVersion) return true;
        }
    }
});

[编辑] Jack 编辑了他的问题,说他不想使用 JavaScript 函数,而是使用简单的表达式。我认为这是不可能的。

【讨论】:

  • 谢谢。请看我的编辑。
猜你喜欢
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多