【问题标题】:Update MongoDB collection based on values from an object根据对象的值更新 MongoDB 集合
【发布时间】:2020-11-07 15:45:57
【问题描述】:

我有一个如下所示的 MongoDB 集合:

[
  {
    "stock": "GOOGLE",
    "price": 0
  },
  {
    "stock": "FACEBOOK",
    "price": 0
  }
]

我有一个像这样的Stock_Prices 对象

{
  "GOOGLE": {
    "price": 31.35
  },
  "FACEBOOK": {
    "price": 10.75
  }
}

我需要使用 Node.js 从 Stock_Prices 对象更新集合中的每只股票。

我想到了以下方法:

  • 遍历集合文档
  • 对于每个文档,获取“stock”字段值(GOOGLE、FACEBOOK)
  • Stock_Prices[document.stock].price中提取价格
  • 更新文档

这是一种不可接受的方法,因为我有成千上万条记录,需要立即更新。

更新:没必要,它应该是更新操作 - 如果是查找,那么我相信也会完成工作

我该怎么做?

【问题讨论】:

  • 你不能遍历Stock_Prices 键并更新每个文档而不检索所有文档,如下所示:YourModel.updateOne(stock, { price })
  • 会有什么不同?我还在一一更新。
  • 更新报价中的最后一条语句对我来说仍然不是很清楚。您要更新还是可以有聚合输出?

标签: javascript node.js mongodb typescript mongoose


【解决方案1】:

您必须获取您的 对象 并将其转换为数组并将其传递给聚合管道。

const stocksMap = {
  "GOOGLE": {
    "price": 31.35
  },
  "FACEBOOK": {
    "price": 10.75
  }
}

const stocks = Object.entries(stocksMap).map(([stock, price]) => ({ stock, price : price.price }))

/* You will get something like this
[{
  "stock": "GOOGLE",
  "price": 31.35
}, {
  "stock": "FACEBOOK",
  "price": 10.75
}]
*/

/* If you want to just read the data, without updating */

db.stocks.aggregate([
  {
    $set: {
      price: {
        $reduce: {
          input: stocks,
          initialValue: 0,
          in: {
            $cond: [
              { $eq: ["$$this.stock", "$stock"] },
              "$$this.price",
              "$$value"
            ]
          }
        }
      }
    }
  }
])

/* If you want to update the existing data, you can use the same pipeline in an aggregation (available from v4.2) */

db.stocks.update({}, [
  {
    $set: {
      price: {
        $reduce: {
          input: stocks,
          initialValue: 0,
          in: {
            $cond: [
              { $eq: ["$$this.stock", "$stock"] },
              "$$this.price",
              "$$value"
            ]
          }
        }
      }
    }
  }
])

如果您不想更新文档,可以将stocks 放在另一个集合中,然后改用$lookup。那应该更高效。

【讨论】:

  • 这是一些怪物查询。谢谢!我去看看!
【解决方案2】:

我将从帖子中取出一个库存对象并展示如何更新:

var stock_price =  { "GOOGLE": { "price": 31.35 } }  // this is the input

var stock_price_doc = Object.keys(stock_price).map (k => ( {field: k, value: stock_price[k] } ) )[0]

stock_price_doc 现在有这个值:{ "field" : "GOOGLE", "value" : { "price" : 31.35 } }

集合的文档(来自帖子):

{
    "stock": "GOOGLE",
    "price": 0
}

更新操作:

db.stocks.update(
  { stock: stock_price_doc.field },
  { $set: { price: stock_price_doc.value.price } }
)

更新后的文档(结果):

{ "stock" : "GOOGLE", "price" : 31.35 }

如果更新是增加股票价格,而不是设置值使用这个:

{ $inc: { price: stock_price_doc.value.price } }

【讨论】:

  • 欣赏它,但我仍然必须为每个公司创建stock_price_doc,对吗?还是一个一个/一步一步的过程吧?
  • 您可以尝试不同的方法。一种方法是,您可以创建一个对象数组,遍历它们并处理数组的每个元素并一次更新一个。这将是多次访问服务器。为避免这些行程,您可以使用Bulk Write Operations(查找批量更新)将所有更新批量发送到服务器(这将是一种高效的操作)。
猜你喜欢
  • 2021-09-30
  • 1970-01-01
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 2016-11-20
  • 2020-07-24
  • 2017-12-29
  • 1970-01-01
相关资源
最近更新 更多