猫鼬findOneAndUpdate:创建然后更新嵌套数组 [英] Mongoose findOneAndUpdate: create and then update nested array

查看:157
本文介绍了猫鼬findOneAndUpdate:创建然后更新嵌套数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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. 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.

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

I'm using findOndAndUpdate to create/update the document for each weather station, but am having trouble updating the arrays within the data object. (Probably not the best way to describe it...)

例如,这是模型:

    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对象看起来像这样:

where the dates object looks like this:

    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.....

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

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

但是这样输出到mlab:

but got an output into mlab like this:

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

问题是我得到的是"0"而不是一个元素的数组.我尝试了"data [0] .maxT",但是当我这样做时什么也没有发生.

the issue is that I get a "0" instead of an array of one element. I tried 'data[0].maxT' but nothing happens when I do that.

问题是,我第一次为工作站运行数据时,我想在我的第三个代码块中创建一个格式为data对象的新文档,然后在后续运行中,一旦该文档已经存在,就进行更新具有新值的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. Any ideas?

推荐答案

您将获得以下输出:

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

因为您要升级文档.处理文档数组时,上线会变得有些复杂.

because you are upserting the document. Upserting gets a bit complicated when dealing with arrays of documents.

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

When updating an array, MongoDB knows that data.0 refers to the first element in the array. However, when inserting, MongoDB can't tell if it's meant to be an array or an object. So it assumes it's an object. So rather than inserting ["val"], it inserts {"0": "val"}.

最简单的解决方案

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

Don't use an upsert. Insert a document for each new weather station then use findOndAndUpdate to push values into the arrays in the documents. As long as you insert the arrays correctly the first time, you will be able to push to them without them turning into objects.

如果data仅包含一个对象的替代简单解决方案

Alternative Simple Solution if data just Contains one Object

从您的问题来看,看来您在data中只有一个对象.在这种情况下,您可以将maxT数组设为顶级,而不是将其作为数组中单个文档的属性.然后它的作用就像dates.

From your question, it looks like you only have one object in 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. Then it would act just like dates.

更复杂的MongoDB 3.6解决方案

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

If you truly cannot do without upserts, MongoDB 3.6 introduced the filtered positional operator $[<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.

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

You can read more about this operator here: https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/

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

So your data objects will need to have a field which can be matched exactly on (say 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.

此外,mLab当前不支持MongoDB 3.6.因此,只有在支持3.6时,该方法在使用mLab时才可行.

Moreover mLab currently does not support MongoDB 3.6. So this method won't be viable when using mLab until 3.6 is supported.

这篇关于猫鼬findOneAndUpdate:创建然后更新嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆