mongoose 如何更新内嵌数组对象的数据?

ideacco:折腾了一晚上,文档看完了,谷歌操作一顿,没搞定。只能求助大神啦。

我有一个数据表 Schema 大概如下:

// PostCountry 表
const PostCountrySchema = new Schema({
  uid: {
    type: ObjectId,
    ref: 'User',
    index: true,
    required: true
  },
  pid: {
    type: String,
    ref: 'Product',
    index: { unique: true }, // 设为唯一的
    required: true
  },
  country_list: [
    {
      country_name: {
        type: String,
        required: true
      },
      country_code: String,
      fourPx_code: {
        type: String,
        default: ''
      },
      declared: { // 申报单价
        type: Number,
        default: 0
      },
      fourPx_send_name: {
        type: String,
        default: ''
      }
    }
  ]
}


数据示例如下:

// PostCountry 表

"country_list": [
        {
            "country_name": "China",
            "declared": 3,
            "fourPx_send_name": "中国邮政"
        },
        {
            "country_name": "Ecuador",
            "declared": 21,
            "fourPx_send_name": "中国邮政"
        },
        {   
            "country_name": "Argentina",
            "declared": 14,
            "fourPx_send_name": "中国邮政"
        }
    ],
    "pid": "5380578836639",
    "uid": "5f7205b75e08ebr1dab5abfa"


我现在需要更新 PostCountry 表中嵌套数组的,fourPx_send_name 数据,如果数据存在则更新,如果不存在则在这个表内增加新的数组。

我 post 填充的数据是:

{
    "country_name": "Canada",
    "declared": 123,
    "fourPx_send_name": "中国邮 31231 政",
    "pid":"5380578836639"
}

我用过的方法 1:

const Data = await PostCountrySchema.findOneAndUpdate({
      uid: ctx.cookies.get('uid'),
      pid: psotData.pid,
      country_list: {
        $elemMatch: {
          country_name: psotData.country_name
        }
      }
    },
    {
      $set: {
        'country_list.$.fourPx_send_name': psotData.fourPx_send_name,
        'country_list.$.declared': psotData.declared
      }
    },
    { new: true, upsert: true, setDefaultsOnInsert: true })
      .then((data) => {
        return data
      })
      .catch(err => console.error('返回错误' + err))

这样操作会返回一个错误 MongoError: Updating the path 'country_list.$.fourPx_send_name' would create a conflict at 'country_list'

我用过的方法 2:

const Data = await PostCountrySchema.findOneAndUpdate({
      uid: ctx.cookies.get('uid'),
      pid: psotData.pid,
      'country_list.country_name': { $ne: psotData.country_name }
    },
    {
       $addToSet: {
        country_list: {
          country_name: psotData.country_name,
          fourPx_send_name: psotData.fourPx_send_name,
          declared: psotData.declared
        }
      }
    },
    { new: true, upsert: true, setDefaultsOnInsert: true })
      .then((data) => {
        return data
      })
      .catch(err => console.error('返回错误' + err))

这样操作,如果 country_name 字段名字没搜索到,是可以添加成功的,然而再次提交修改就会报错了:

MongoError: E11000 duplicate key error collection: shopify.post_country index: pid_1 dup key: { pid: "5380578836639" }

操作 3,将 上面的 $addToSet 改成$push 结果也是一样,没有数据可以填充,有数据就无法填充了。

如何才可以根据条件更新内嵌数组的数据,如无数据则新增数组,如果有数据则更新数组?

折磨了半天了,求大神支个招吧。

libook:https://docs.mongodb.com/manual/reference/operator/update/addToSet/#value-to-add-is-a-document
$addToSet 必须得是字段和值完全一样才会认为不需要插入,也就是说顶多做插入,跟更新数据没关系。

你要是非要按照现有的 schema 来做,只能用程序先遍历 country_list,找到一样的 fourPx_send_name 就修改数据,然后整个 document save 。

MongoDB 操作的最小单位是文档(Document),你现在操作的是子文档,所以会很麻烦。

对于需要频繁对你现在操作的是子文档操作的场景,应该把你现在操作的是子文档抽出来做成一个新的 Collection,然后用 ref 和 populate 来与 PostCountry 建立关系。

libook:对于需要频繁操作子文档的场景,应该把子文档抽出来做成一个新的 Collection,然后用 ref 和 populate 来与 PostCountry 建立关系。

mongoose 聚合管道查询, list 中的子对象如何关联?

ideacco:RT,使用 mongoose,有如下两个数据,我想把产品参数据表,对应的产品查询出来,我目前只会查询一级的,在 Array 里面包裹的数据就不知道怎么取出来了,看了一天的官网文档也没看明白……惭愧惭愧,求大神给指个道吧。 示例数据如下: // 产品数据表 product { "uid": "5f460572f639b62baa839baa",…

正确的JNDI @Resource(name) - java

我有以下用于获取JDBC连接的类:package util; import java.sql.Connection; import java.sql.SQLException; import javax.annotation.Resource; import javax.naming.Context; import javax.naming.InitialC…

求助大佬呀

xiaoniuniu:/** 编写一个 js 方法根据输入实现输出 将 arr 转化为树形结构 treeObj 节点的 outputs 为下一节点的 inputs */ 例子: // 输入 const arr = [{ name: 'test1', outputs: [1,2], inputs: [] }, { name: 'test2', outputs:…

三步带你开发一个短链接生成平台

GrapeCityChina:前端时间在开发 [葡萄城社区] 公众号时有一个功能是需要用网页授权认证地址生成二维码,但类似像下面这样的 Url 即便是看也觉得很头疼了 https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxxxxxxxxxx&redirect_uri=xx…

求助一条 MYSQL 查询语句,以甲表字段内容,查出乙表的另外一个字段内容,合并输出。。。

qazwsxkevin:stu 表有一个字段是"name" name 有重复 registu 表也有`name`和`stuid`两个字段 把 stu 表里的 name + registu 表的`stuid`,查询出来,感谢各位解答...Gatsbywl:join 连接? yeqizhang:你没解释清楚。你重复名字,应该是不同人?反正就是连接查询,结果中拼接…