简体   繁体   English

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

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

I have a program where I'm requesting weather data from a server, processing the data, and then saving it to an mlab account using mongoose. 我有一个程序,用于从服务器请求天气数据,处理数据,然后使用猫鼬将其保存到mlab帐户。 I'm gathering 10 years of data, but the API that I'm requesting the data from only allows about a year at a time to be requested. 我正在收集10年的数据,但是我从中请求数据的API一次只能允许大约一年的时间。

I'm using findOndAndUpdate to create/update the document for each weather station, but am having trouble updating the arrays within the data object. 我正在使用findOndAndUpdate为每个气象站创建/更新文档,但是在更新数据对象内的数组时遇到了麻烦。 (Probably not the best way to describe it...) (可能不是描述它的最佳方式...)

For example, here's the model: 例如,下面是模型:

    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 }
     )

where the dates object looks like this: 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"]

and the data object like this: 和这样的数据对象:

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

what I want to have happen is when I run findOneAndUpdate I want to find the document based on the station, and then append new maxT values and dates to the respective arrays. 我想要发生的是,当我运行findOneAndUpdate时,我想根据工作站查找文档,然后将新的maxT值和日期附加到相应的数组中。 I have it working for the date array, but am running into trouble with the data array as the elements I'm updated are nested. 我有它为日期数组工作,但由于我要更新的元素是嵌套的,所以数据数组遇到麻烦。 I tried this: 我尝试了这个:

    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')

but got an output into mlab like this: 但是这样输出到mlab:

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

the issue is that I get a "0" instead of an array of one element. 问题是我得到的是“ 0”而不是一个元素的数组。 I tried 'data[0].maxT' but nothing happens when I do that. 我尝试了“ data [0] .maxT”,但是这样做没有任何反应。

The issue is that the first time I run the data for a station, I want to create a new document with data object of the format in my third code block, and then on subsequent runs, once that document already exists, update the maxT array with new values. 问题是,第一次运行工作站数据时,我想在第三个代码块中创建一个格式为data对象的新文档,然后在后续运行中,一旦该文档已存在,请更新maxT数组具有新的价值。 Any ideas? 有任何想法吗?

You are getting this output: 您将得到以下输出:

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

because you are upserting the document. 因为您正在整理文档。 Upserting gets a bit complicated when dealing with arrays of documents. 处理文档数组时,上装会变得有些复杂。

When updating an array, MongoDB knows that data.0 refers to the first element in the array. 更新数组时,MongoDB知道data.0指向数组中的第一个元素。 However, when inserting, MongoDB can't tell if it's meant to be an array or an object. 但是,在插入时,MongoDB不能确定它是数组还是对象。 So it assumes it's an object. 因此,它假定它是一个对象。 So rather than inserting ["val"] , it inserts {"0": "val"} . 因此,它不会插入["val"] ,而是插入{"0": "val"}


Simplest Solution 最简单的解决方案

Don't use an upsert. 不要使用upsert。 Insert a document for each new weather station then use findOndAndUpdate to push values into the arrays in the documents. 为每个新气象站插入一个文档,然后使用findOndAndUpdate将值推入文档中的数组。 As long as you insert the arrays correctly the first time, you will be able to push to them without them turning into objects. 只要您第一次正确插入数组,就可以将它们压入它们而不会变成对象。


Alternative Simple Solution if data just Contains one Object 如果data仅包含一个对象,则为另一种简单解决方案

From your question, it looks like you only have one object in data . 从您的问题来看,您似乎在data只有一个对象。 If that is the case, you could just make the maxT array top-level, instead of being a property of a single document in an array. 如果是这种情况,您可以将maxT数组maxT顶级,而不是成为数组中单个文档的属性。 Then it would act just like dates . 然后它就像dates一样。


More Complicated MongoDB 3.6 Solution 更复杂的MongoDB 3.6解决方案

If you truly cannot do without upserts, MongoDB 3.6 introduced the filtered positional operator $[<identifier>] . 如果您真的不能没有upserts,MongoDB 3.6就会引入过滤后的位置运算符$[<identifier>] You can use this operator to update specific elements in an array which match a query. 您可以使用此运算符来更新与查询匹配的数组中的特定元素。 Unlike the simple positional operator $ , the new $[<identifier>] operator can be used to upsert as long as an exact match is used. 与简单的位置运算符$ ,只要使用精确匹配,新的$[<identifier>]运算符就可以用于补高。

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

So your data objects will need to have a field which can be matched exactly on (say name ). 因此,您的data对象将需要具有一个可以完全匹配的字段(例如name )。 An example query would look something like this: 查询示例如下所示:

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)

As you can see this adds much more complexity. 如您所见,这增加了更多的复杂性。 It would be much easier to forget about trying to do upserts. 忘记尝试进行增补会容易得多。 Just do one insert then update. 只需插入一个然后更新。

Moreover mLab currently does not support MongoDB 3.6. 而且,mLab当前不支持MongoDB 3.6。 So this method won't be viable when using mLab until 3.6 is supported. 因此,只有在支持3.6之前,使用mLab时该方法才可行。

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

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