将猫鼬中的字段设置为数组长度

时间:2019-05-07 14:26:05

标签: javascript node.js mongoose

我有一个猫鼬的文档:

var SkillSchema = new mongoose.Schema({
    skill: { type: String },
    tally: { type: Number, default: 0 },
    associatedUsers: { type: Array }
});

我正在更新如下:

var query = {skill: req.body.skill};
var update = {
    $addToSet: {
        associatedUsers: res.locals.currentUser._id
    },
    {
};

var options = { upsert: true, new: true, setDefaultsOnInsert: true };

await skillSchema.findOneAndUpdate(query, update, options);

在此更新期间,我还要将tally更新为等于associatedUsers的长度。

理想情况下,我希望通过pre-hookfindOneAndUpdate在更新其他字段的同时进行此操作(而不是在后续更新中)。

我尝试在模式定义后使用预钩子:

SkillSchema.pre('findOneAndUpdate', async function(){
    console.log("counting associated users");
    this.tally = this.associatedUsers.length;
    next();
});

以及在我的UPDATE路由中使用aggregate

await skillSchema.aggregate([{ $project: { tally: { $size: "$associatedUsers" } } } ])

但是我都不能上班。

有人对我如何实现这一目标有任何建议吗?

4 个答案:

答案 0 :(得分:6)

您可以在4.2中像这样使用$set,它支持更新中的聚合管道。

第一个$ set阶段根据先前和新的值计算一个associatedUsers$setUnion保留不同的associatedUsers值。

第二个$ set阶段基于上一个阶段中计算的tally计算associatedUsers$size来计算relatedUsers值的长度。

var query = {skill: req.body.skill};
var update = [{ $set: { "associatedUsers":{"$setUnion":[{"$ifNull":["$associatedUsers",[]]}, [req.params.id]] }}}, {$set:{tally:{ $size: "$associatedUsers" }}}];
var options = { upsert: true, new: true, setDefaultsOnInsert: true };
await skillSchema.findOneAndUpdate(query, update, options)

如果任何参数解析为null值或引用缺少的字段,则$ setUnion返回null。因此,只需使用$ifNull

来保护我们的运营

答案 1 :(得分:1)

关于提示和相关用户长度

helm

编辑 您可以随后更新提示,但是建议的解决方案是使用此方法 https://mongoosejs.com/docs/populate.html

// define your schema object
var schemaObj = {
  skill: { type: String },
  associatedUsers: { type: Array }
};

// get the length of users
var lengthOfAsUsers = schemaObj.associatedUsers.length;

// add tally to schema object and set default to the length of users
schemaObj.tally = { type: Number, default: lengthOfAsUsers };

// and pass your schema object to mongoose.Schema
var SkillSchema = new mongoose.Schema(schemaObj);

module.exports = SkillSchema;

答案 2 :(得分:1)

我拥有的解决方案仅适用于mongodb v 4.2,因为它具有在更新中使用聚合的选项,并且只需一个查询即可:

skillSchemafindOneAndUpdate(


 {skill:"art"},
   [
     { $set: { 
       associatedUsers:{
         $cond:{
            if: {$gte: [{$indexOfArray: ["$associatedUsers", mongoose.Types.ObjectId(req.params.id)]}, 0]},
              then: "$associatedUsers",
              else: { $cond:{
                if: { $isArray: "$associatedUsers" },
                then: {$concatArrays:["$associatedUsers",[mongoose.Types.ObjectId(req.params.id)]]},
                else: [mongoose.Types.ObjectId(req.params.id)]
           }}
           }
      }}},
      {$set:{
        associatedUsers:"$associatedUsers",
        tally:{$size:"$associatedUsers"},
      }}
   ],
   {upsert:true,new:true}
)

ref:https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline

答案 3 :(得分:0)

“组”字段未出现在架构中。在MongoDB Shell上,这些代码将起作用。

但是,由于该模式已验证,猫鼬也会给出一个错误。

“组”字段是动态字段吗?我认为该模式的问题将得到解决。

import seaborn as sb
import matplotlib.pyplot as plt
font = {'family': 'serif',
        'color':  '#3c4043',
        'weight': 'normal',
        'size': 16,
        }
f, ax = plt.subplots(nrows = 1, ncols = 1,figsize=(12, 8))
ax.set_xlabel("Models", labelpad=20, fontdict=font)
ax.set_ylabel("RMSE", labelpad=10, fontdict=font)
fig = sb.boxplot(x=names, y=results)