【问题标题】:MongoDB/Mongoid: search for documents matching first item in arrayMongoDB/Mongoid:搜索匹配数组中第一项的文档
【发布时间】:2013-03-28 12:27:18
【问题描述】:

我有一个包含数组的文档:

{
    _id: ObjectId("515e10784903724d72000003"),
    association_chain: [
        {
            name: "Product",
            id: ObjectId("4e1e2cdd9a86652647000003")
        }
    ],
    //...
}

我正在尝试在集合中搜索 name 数组中第一项的 name 与给定值匹配的文档。

如何使用 Mongoid 做到这一点?或者,如果您只知道如何使用 MongoDB 来完成,如果您发布一个示例,那么我可能会弄清楚如何使用 Mongoid 来完成。

【问题讨论】:

    标签: ruby-on-rails mongodb mongoid mongoid3


    【解决方案1】:

    两种方法:

    1) 如果您已经知道您只对出现在“association_chain”中的第一个产品名称感兴趣,那么这样会更好:

    db.items.find("association_chain.0.name":"something")
    

    请注意,这不会返回所有提及所需产品的项目,而只会返回那些在“association_chain”数组的第一个位置提及的项目。

    如果你想这样做,那么你需要一个索引:

    db.items.ensureIndex({"association_chain.0.name":1},{background:1})
    

    2) 如果您正在寻找特定产品,但不确定它出现在 Association_chain 的哪个位置,请执行以下操作:

    使用 MongoDB shell,您可以使用 '.' 访问嵌套结构内的任何哈希键。点运算符!请注意,这与该键在记录中嵌套的深度无关(不是很酷吗?)

    您可以像这样对嵌入的哈希数组进行查找:

    db.items.find("association_chain.name":"something")
    

    这将返回集合中包含关联数组中任何位置提到的所需产品的所有记录。

    如果你想这样做,你应该确保你有一个索引:

    db.items.ensureIndex({"association_chain.name":1},{background: 1})
    

    请参阅此页面上的“点符号”:http://docs.mongodb.org/manual/core/document/

    【讨论】:

    • 第二个代码块应该是'db.items.ensureIndex',而不是'.find'
    【解决方案2】:

    使用位置运算符。您可以使用.0 查询数组的第一个元素(使用.1 等查询第二个元素)。

    > db.items.insert({association_chain: [{name: 'foo'}, {name: 'bar'}]})
    > db.items.find({"association_chain.0.name": "foo"})
    { "_id" : ObjectId("516348865862b60b7b85d962"), "association_chain" : [ { "name" : "foo" }, { "name" : "bar" } ] }
    

    您可以看到位置运算符有效,因为在第二个元素中搜索 foo 不会返回命中...

    > db.items.find({"association_chain.1.name": "foo"})
    >
    

    ...但是搜索bar 可以。

    > db.items.find({"association_chain.1.name": "bar"})
    { "_id" : ObjectId("516348865862b60b7b85d962"), "association_chain" : [ { "name" : "foo" }, { "name" : "bar" } ] }
    

    你甚至可以索引这个特定的字段,而不用索引所有关联链文档的所有名称:

    > db.items.ensureIndex({"association_chain.0.name": 1})
    > db.items.find({"association_chain.0.name": "foo"}).explain()
    {
            "cursor" : "BtreeCursor association_chain.0.name_1",
            "nscanned" : 1,
            ...
    
    }
    > db.items.find({"association_chain.1.name": "foo"}).explain()
    {
            "cursor" : "BasicCursor",
            "nscanned" : 3,
            ...
    }
    

    【讨论】:

    • 我不知道你可以像这样滥用索引。喜欢它。
    【解决方案3】:

    您可以使用聚合框架来做到这一点。在 mongo shell 中运行一个展开文档的查询,以便每个数组元素都有一个文档(在其他字段中有重复的数据),然后按 id 和要包含的任何其他字段分组,加上带有运算符 $first 的数组.然后只需包含 $match 运算符即可按名称或 mongoid 进行过滤。

    这是要与第一个产品名称匹配的查询:

    db.foo.aggregate([
    { $unwind:"$association_chain"     
    },
    {
      $group : {
                "_id" : {
                    "_id" : "$_id",
                    "other" : "$other"
                },
                "association_chain" : {
                    $first : "$association_chain"
                }
            }
    },
    {  $match:{ "association_chain.name":"Product"}
    }
    
    ])
    

    下面是通过mongoid查询第一个产品的方法:

    db.foo.aggregate([
    { $unwind:"$association_chain"     
    },
    {
       $group : {
                "_id" : {
                    "_id" : "$_id",
                    "other" : "$other"
                },
                "association_chain" : {
                    $first : "$association_chain"
                }
            }
    },
    {  $match:{ "association_chain.id":ObjectId("4e1e2cdd9a86652647000007")}
    }
    
    ])
    

    【讨论】:

    • 使用我提到的聚合框架或使用点表示法的简单查询之间的区别在于,使用点表示法将返回整个文档,包括数组 association_chain 的所有元素。将此查询与聚合一起使用将返回仅包含数组中匹配的元素(第一个)的文档,或者您可以以任何您想要的方式转换文档。使用最适合您需求的那一款。
    猜你喜欢
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 2014-11-06
    • 2021-11-16
    • 2012-03-14
    相关资源
    最近更新 更多