猫鼬-如果数组更新则推送

时间:2020-09-16 11:50:24

标签: node.js mongodb mongoose

我的架构如下:

{
    _id: mongoose.Schema.Types.ObjectId,
    timestamp: { type: Date, default: Date.now },
    uid: { type: String, required: false, immutable: true },
    gid: [
        {
            type: String
        }
    ],
    status: { type: String, required: false }
}

我希望每次uid是新对象时都可以保存一个新对象,并在已有对象时对其进行更新。因此,基本上保存此对象:

{
uid: "xyz",
gid: "123"
}

应该产生

{
_id: ObjectId("123"),
uid: "xyz",
gid: ["123"]
// note that if status is not provided it shouldn't appear here as `null`
}

然后再次保存该对象:

{
uid: "xyz",
gid: "345",
status: "new"
}

它应该产生:

{
_id: ObjectId("123"),
uid: "xyz",
gid: ["123","345"]
status: "new"
}

最后是这个对象:

{
uid: "xyz",
gid: "345",
status: "old"
}

预期结果将是

{
_id: ObjectId("123"),
uid: "xyz",
gid: ["123","345"]
status: "old"
}

这可以在单个查询中实现吗?抱歉,如果我的求职过程很复杂,我不知道该怎么办。

2 个答案:

答案 0 :(得分:0)

案例1:仅状态更改和数组存在,下面的代码将不会添加新元素

> //actual code output from Mongo shell 4.2 on windows10 OS
> //use add to set and set update to acheive your update goals(array vs addition
> //of fields in two updates
> //add to set checks for an array element is present in array, if it is present it does nothing
> //else it will add the element in the array
> //pre-update document check
> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200"
        ],
        "status" : "old"
}
> var v_status = "new";
> db.ugs.aggregate([
... {$match:{uid: "xyz"}}
... ]).forEach(function(doc){
...     print("uid: ", doc.uid);
...     print("gid: ",doc.gid);
...     print("pre-status: ", doc.status);
...     db.ugs.update(
...     {"_id":doc._id},
...     {$addToSet:{gid:"200"}
...     });
...     db.ugs.update(
...     {"_id":doc._id},
...     {$set:{status:v_status}}
...     );
...     print("post-status: ", v_status);
... });
uid:  xyz
gid:  345,123,100,200
pre-status:  old
post-status:  new
> //post update document check
> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200"
        ],
        "status" : "new"
}
>

情况2:如果数组中不存在元素,请更改状态并添加元素

> //pre-update document check
> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200"
        ],
        "status" : "new"
}
> var v_status = "old";
> db.ugs.aggregate([
... {$match:{uid: "xyz"}}
... ]).forEach(function(doc){
...     print("uid: ", doc.uid);
...     print("gid: ",doc.gid);
...     print("pre-status: ", doc.status);
...     db.ugs.update(
...     {"_id":doc._id},
...     {$addToSet:{gid:"444"}
...     });
...     db.ugs.update(
...     {"_id":doc._id},
...     {$set:{status:v_status}}
...     );
...     print("post-status: ", v_status);
... });
uid:  xyz
gid:  345,123,100,200
pre-status:  new
post-status:  old
> //post update document check
> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200",
                "444"
        ],
        "status" : "old"
}
>

情况3:根据需要设置和取消设置状态字段的值。

> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200",
                "444"
        ],
        "status" : ""
}
> var v_status = "";
> db.ugs.aggregate([
... {$match:{uid: "xyz"}}
... ]).forEach(function(doc){
...     print("uid: ", doc.uid);
...     print("gid: ",doc.gid);
...     print("pre-status: ", doc.status);
...     db.ugs.update(
...     {"_id":doc._id},
...     {$addToSet:{gid:"444"}
...     });
...     db.ugs.update(
...     {"_id":doc._id,status:{$exists:true}},
...     {$set:{status:v_status}}
...     );
...     print("post-status: ", v_status);
... });
uid:  xyz
gid:  345,123,100,200,444
pre-status:
post-status:
> //post update document check
> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200",
                "444"
        ],
        "status" : ""
}
//unset the field if not required, it will not show in the document
> var v_status = "";
> db.ugs.aggregate([
... {$match:{uid: "xyz"}}
... ]).forEach(function(doc){
...     print("uid: ", doc.uid);
...     print("gid: ",doc.gid);
...     print("pre-status: ", doc.status);
...     db.ugs.update(
...     {"_id":doc._id},
...     {$addToSet:{gid:"444"}
...     });
...     db.ugs.update(
...     {"_id":doc._id,status:{$exists:true}},
...     {$unset:{status:v_status}}
...     );
...     print("post-status: ", v_status);
... });
uid:  xyz
gid:  345,123,100,200,444
pre-status:  [unknown type]
post-status:
> //post update document check
> db.ugs.find().pretty();
{
        "_id" : ObjectId("5f625d864651219e25c775c1"),
        "uid" : "xyz",
        "gid" : [
                "345",
                "123",
                "100",
                "200",
                "444"
        ]
}
>

答案 1 :(得分:0)

您正在寻找upsert选项来添加新文档(如果尚不存在)。与addToSet原子运算符结合使用,创建了一个gid数组。

您必须将其余部分分解为$ set和$ addToSet更新程序。

let saveObj = {
  uid: "xyz",
  gid: "123"
};

let {gid, ...setFields} = saveObj;

YourModel.updateOne(
  {uid: setFields.uid},
  {$set: setFields, $addToSet: {gid}},
  {upsert: true}
).then(...);