【问题标题】:Only return some of the fields from list of embedded documents只返回嵌入文档列表中的一些字段
【发布时间】:2016-03-31 07:22:18
【问题描述】:

这是我的文件:

{
"_id" : "2",
"account" : "1234",
"positions" : { 
  "APPL" : { "quantity" : "13", "direction" : "long" }, 
  "GOOG" : { "quantity" : "24", "direction" : "long" }
 }
}

我想获取整个 positions 对象,但只有 quantity 字段ignore 方向字段。有可能这样做吗?或者我应该考虑这个其他模式(对象数组):

{
"_id" : "2",
"account" : "1234",
"positions" : [ 
  { "name" : "APPL", "quantity" : "13", "direction" : "long" }, 
  { "name" : "GOOG", "quantity" : "24", "direction" : "long" }
 ]
}

非常感谢!

【问题讨论】:

  • 使用数组。 MongoDB 运算符不能“遍历”对象的键。使用键,您需要明确命名每个键。

标签: javascript mongodb mapreduce mongodb-query


【解决方案1】:

对于“数组”表单,您真正需要做的就是使用"dot notation" 为数组成员指定字段:

db.collection.find({}, { "positions.quantity": 1, })

哪个会返回:

{
  "_id" : "2",
  "positions" : [
    { "quantity" : "13" },
    { "quantity" : "24" }
  ]
}

或者对于多个字段,但不包括"direction",只需在投影中同时使用:

db.collection.find({},{ "positions.name": 1, "positions.quantity": 1 })

仍然返回命名字段:

{
  "_id" : "2",
  "positions" : [
    {
            "name" : "APPL",
            "quantity" : "13"
    },
    {
            "name" : "GOOG",
            "quantity" : "24"
    }
  ]
}

对于“命名键”表单,您需要指定每个路径:

db.collection.find({},{ "positions.APPL.quantity": 1, "positions.GOOG.quantity": 1  })

当然会返回:

{
  "_id" : "2",
  "positions" : {
    "APPL" : {
      "quantity" : "13"
    },
    "GOOG" : {
      "quantity" : "24"
    }
  }
}

这种“讨厌”在基本上 ALL MongoDB 操作、查询或投影或其他方面普遍存在。当您使用“命名键”时,“数据库”除了要求您“命名路径”之外没有任何明智的选择。当集合中的文档之间的键名可能不同时,这样做当然不是真正的实际练习。

从 MongoDB 的角度来看,遍历键只能在 JavaScript 评估中真正完成。由于 JavaScript 评估在启动和将数据从 BSON 转换为可用的 JavaScript 格式时需要解释器成本,更不用说评估编码表达式本身的实际成本,这不是一种理想的方法。

此外,从“查询”的角度来看,此类处理需要使用 $where 来评估这样的表达式,您只想在 "positions" 数据的每个“键”下查找内容。这是一件“坏事”,因为这样的表达式不可能使用“索引”来优化查询搜索。只有使用“直接命名的路径”,您才能在这些条件下实际使用甚至“创建”索引。

从“投影”的角度来看,“命名键”的使用意味着通过类似的“遍历”概念,您实际上需要再次进行 JavaScript 处理才能这样做。 MongoDB 可以使用 JavaScript 表达式“更改”输出文档的 only 机制是使用mapReduce,所以这又是“超级可怕”,您将使用这种“聚合方法”在这种情况下,仅用于文档操作:

db.collection.mapReduce(
    function() {
        var id = this._id;
        delete this._id;
        Object.keys(this.positions).forEach(function(el) {
            delete el.direction;
        });
        emit(id,this);
    },
    function() {},    // reducer never gets called when all are unique
    { "out": { "inline": 1 } }
)

即使您这样做只是为了避免命名路径,mapReduce 的输出也不能是“光标”。因此,这将您限制为响应 实际输出到“集合”的 BSON 文档的大小。所以这与你所能得到的“实用”相去甚远。


“为什么”使用具有“公共路径”的数组比使用“命名键”结构要好得多的原因有很多,这些结构也过于宽泛,无法在此处介绍。您应该接受的一件事是“命名的键是不好的,好吧!” 然后继续使用一致的对象命名,这实际上很有意义。

【讨论】:

  • 我一直在寻找这种答案和非常好的解释。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-12
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 2015-03-26
相关资源
最近更新 更多