繁体   English   中英

猫鼬findOneAndUpdate:创建然后更新嵌套数组

[英]Mongoose findOneAndUpdate: create and then update nested array

我有一个程序,用于从服务器请求天气数据,处理数据,然后使用猫鼬将其保存到mlab帐户。 我正在收集10年的数据,但是我从中请求数据的API一次只能允许大约一年的时间。

我正在使用findOndAndUpdate为每个气象站创建/更新文档,但是在更新数据对象内的数组时遇到了麻烦。 (可能不是描述它的最佳方式...)

例如,下面是模型:

    const stnDataSchema = new Schema(
       { 
        station: { type: String, default: null }, 
        elevation: { type: String, default: null },
        timeZone: { type: String, default: null },
        dates: {},
        data: {}
       }, 
       { collection: 'stndata' },
       { runSettersOnQuery: true }
     )

date对象看起来像这样:

    dates: ["2007-01-01",
    "2007-01-02",
    "2007-01-03",
    "2007-01-04",
    "2007-01-05",
    "2007-01-06",
    "2007-01-07",
    "2007-01-08",
    "2007-01-09"]

和这样的数据对象:

    "data": [
       {
        "maxT": [
            0,
            null,
            4.4,
            0,
            -2.7,
            etc.....

我想要发生的是,当我运行findOneAndUpdate时,我想根据工作站查找文档,然后将新的maxT值和日期附加到相应的数组中。 我有它为日期数组工作,但由于我要更新的元素是嵌套的,所以数据数组遇到麻烦。 我尝试了这个:

    const update = {
    $set: {'station': station, 'elevation': elevation, 'timeZone': timeZone},
    $push: {'dates': datesTest, 'data.0.maxT': testMaxT}};
    StnData.findOneAndUpdate( query, update, {upsert: true} ,
    function(err, doc) {
    if (err) {
     console.log("error in updateStation", err)
     throw new Error('error in updateStation')
   }
   else {
     console.log('saved')

但是这样输出到mlab:

    "data": {
      "0": {
          "maxT": [
            "a",
            "b",

问题是我得到的是“ 0”而不是一个元素的数组。 我尝试了“ data [0] .maxT”,但是这样做没有任何反应。

问题是,第一次运行工作站数据时,我想在第三个代码块中创建一个格式为data对象的新文档,然后在后续运行中,一旦该文档已存在,请更新maxT数组具有新的价值。 有任何想法吗?

您将得到以下输出:

 "data": {
    "0": {
      "maxT": [
        "a",
        "b",

因为您正在整理文档。 处理文档数组时,上装会变得有些复杂。

更新数组时,MongoDB知道data.0指向数组中的第一个元素。 但是,在插入时,MongoDB不能确定它是数组还是对象。 因此,它假定它是一个对象。 因此,它不会插入["val"] ,而是插入{"0": "val"}


最简单的解决方案

不要使用upsert。 为每个新气象站插入一个文档,然后使用findOndAndUpdate将值推入文档中的数组。 只要您第一次正确插入数组,就可以将它们压入它们而不会变成对象。


如果data仅包含一个对象,则为另一种简单解决方案

从您的问题来看,您似乎在data只有一个对象。 如果是这种情况,您可以将maxT数组maxT顶级,而不是成为数组中单个文档的属性。 然后它就像dates一样。


更复杂的MongoDB 3.6解决方案

如果您真的不能没有upserts,MongoDB 3.6就会引入过滤后的位置运算符$[<identifier>] 您可以使用此运算符来更新与查询匹配的数组中的特定元素。 与简单的位置运算符$ ,只要使用精确匹配,新的$[<identifier>]运算符就可以用于补高。

您可以在此处了解有关此运算符的更多信息: https : //docs.mongodb.com/manual/reference/operator/update/positional-filtered/

因此,您的data对象将需要具有一个可以完全匹配的字段(例如name )。 查询示例如下所示:

let query = {
  _id: 'idOfDocument', 
  data: [{name: 'subobjectName'}] // Need this for an exact match
}

let update = {$push: {'data.$[el].maxT': testMaxT}}

let options = {upsert: true, arrayFilters: [{'el.name': 'subobjectName'}]}

StnData.findOneAndUpdate(query, update, options, callbackFn)

如您所见,这增加了更多的复杂性。 忘记尝试进行增补会容易得多。 只需插入一个然后更新。

而且,mLab当前不支持MongoDB 3.6。 因此,只有在支持3.6之前,使用mLab时该方法才可行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM