首页 文章

Mongoose:无法使用$ addToSet或$ push将新对象添加/推送到数组

提问于
浏览
7

我使用Nodejs,Hapijs和Mongoose .

我的架构和模型如下 .

var schema = {
    name: {
        type: String,
        required: true
    },
    lectures: {}
};

var mongooseSchema = new mongoose.Schema(schema, {
    collection: "Users"
});
mongoose.model("Users", mongooseSchema);

出于某种原因,我需要将“讲座”作为混合类型 .

在保存/创建文档时,我创建了一个嵌套属性 lectures.physics.topic[] ,其中topic是一个数组 .

现在,我正在尝试使用$ addToSet或$ push将新对象添加/推送到“lectures.physics.topic” .

userModel.findByIdAndUpdateAsync(user._id, {
    $addToSet: {
        "lectures.physics.topic": {
            "name": "Fluid Mechanics",
            "day": "Monday",
            "faculty": "Nancy Wagner"
        }
    }
});

但该文件根本没有得到更新 . 我也试过使用$ push . 没有任何效果 . 可能是什么问题呢?

我试图使用mongoclient的另一种方法,直接更新数据库 . 它的工作原理请找到下面的代码

db.collection("Users").update({
   "_id": user._id
 }, {
 $addToSet: {
        "lectures.physics.topic": {
            "name": "Fluid Mechanics",
            "day": "Monday",
            "faculty": "Nancy Wagner"
        }
    }
 }, function(err, result) {
   if (err) {
       console.log("Superman!");
       console.log(err);
       return;
   }
 console.log(result);     
 });

每次请求被命中时我都必须启动mongo客户端 . 这不是一个可行的解决方案 .

2 回答

  • 1

    我会打电话给"bug" . Mongoose显然做了错误的事情,如后面所示的日志记录中可以证明的那样 . 但是这里有一个列表,它使用您尝试执行的相同更新从本机驱动程序调用 .findOneAndUpdate()

    var async = require('async'),
        mongoose = require('mongoose'),
        Schema = mongoose.Schema;
    
    mongoose.connect('mongodb://localhost/school');
    mongoose.set('debug',true);
    
    var userSchema = new Schema({
      name: {
        type: String,
        required: true
      },
      lectures: { type: Schema.Types.Mixed }
    });
    
    var User = mongoose.model( "User", userSchema );
    
    function logger(data) {
      return JSON.stringify(data, undefined, 2);
    }
    
    async.waterfall(
      [
        function(callback) {
          User.remove({},function(err) {
            callback(err);
          });
        },
        function(callback) {
          console.log("here");
          var user = new User({ "name": "bob" });
          user.save(function(err,user) {
            callback(err,user);
          });
        },
        function(user,callback) {
          console.log("Saved: %s", logger(user));
          User.collection.findOneAndUpdate(
            { "_id": user._id },
            {
              "$addToSet": {
                "lectures.physics.topic": {
                  "name": "Fluid Mechanics",
                  "day": "Monday",
                  "faculty": "Nancy Wagner"
                }
              }
            },
            { "returnOriginal": false },
            function(err,user) {
              callback(err,user);
            }
          );
        }
      ],
      function(err,user) {
        if (err) throw err;
        console.log("Modified: %s", logger(user));
        mongoose.disconnect();
      }
    );
    

    这与结果完美配合:

    Saved: {
      "__v": 0,
      "name": "bob",
      "_id": "55cda1f5b5ee8b870e2f53bd"
    }
    Modified: {
      "lastErrorObject": {
        "updatedExisting": true,
        "n": 1
      },
      "value": {
        "_id": "55cda1f5b5ee8b870e2f53bd",
        "name": "bob",
        "__v": 0,
        "lectures": {
          "physics": {
            "topic": [
              {
                "name": "Fluid Mechanics",
                "day": "Monday",
                "faculty": "Nancy Wagner"
              }
            ]
          }
        }
      },
      "ok": 1
    }
    

    你需要小心,因为本机驱动程序方法不像mongoose方法那样知道连接状态 . 因此,您需要确保通过先前触发的“mongoose”方法 Build 连接,或者将您的应用程序包装在连接事件中,如下所示:

    mongoose.connection.on("connect",function(err) {
       // start app in here
    });
    

    至于“bug”,请查看此列表的日志记录输出:

    var async = require('async'),
        mongoose = require('mongoose'),
        Schema = mongoose.Schema;
    
    mongoose.connect('mongodb://localhost/school');
    mongoose.set('debug',true);
    
    var userSchema = new Schema({
      name: {
        type: String,
        required: true
      },
      lectures: { type: Schema.Types.Mixed }
    });
    
    var User = mongoose.model( "User", userSchema );
    
    function logger(data) {
      return JSON.stringify(data, undefined, 2);
    }
    
    async.waterfall(
      [
        function(callback) {
          User.remove({},function(err) {
            callback(err);
          });
        },
        function(callback) {
          console.log("here");
          var user = new User({ "name": "bob" });
          user.save(function(err,user) {
            callback(err,user);
          });
        },
        function(user,callback) {
          console.log("Saved: %s", logger(user));
          User.findByIdAndUpdate(
            user._id,
            {
              "$addToSet": {
                "lectures.physics.topic": {
                  "name": "Fluid Mechanics",
                  "day": "Monday",
                  "faculty": "Nancy Wagner"
                }
              }
            },
            { "new": true },
            function(err,user) {
              callback(err,user);
            }
          );
        }
      ],
      function(err,user) {
        if (err) throw err;
        console.log("Modified: %s", logger(user));
        mongoose.disconnect();
      }
    );
    

    并且使用mongoose日志记录的记录输出:

    Mongoose: users.remove({}) {}
    here
    Mongoose: users.insert({ name: 'bob', _id: ObjectId("55cda2d2462283c90ea3f1ad"), __v: 0 })
    Saved: {
      "__v": 0,
      "name": "bob",
      "_id": "55cda2d2462283c90ea3f1ad"
    }
    Mongoose: users.findOne({ _id: ObjectId("55cda2d2462283c90ea3f1ad") }) { new: true, fields: undefined }
    Modified: {
      "_id": "55cda2d2462283c90ea3f1ad",
      "name": "bob",
      "__v": 0
    }
    

    所以在真正的"What the Fudge?"风格中,有一个叫 .findOne() 的电话?这不是问的问题 . 此外,当然数据库中没有任何改变,因为进行了错误的调用 . 所以即使这里的 { "new": true } 也是多余的 .

    这种情况发生在具有“混合”模式类型的所有级别 .

    就个人而言,我不会像这样嵌套在“对象”中,只需将“对象键”作为标准数组的一部分作为附加属性 . MongoDB和mongoose都对此更加满意,并且查询具有这种结构的信息要容易得多 .

    var async = require('async'),
        mongoose = require('mongoose'),
        Schema = mongoose.Schema;
    
    mongoose.connect('mongodb://localhost/school');
    mongoose.set('debug',true);
    
    var lectureSchema = new Schema({
      "subject": String,
      "topic": String,
      "day": String,
      "faculty": String
    });
    
    var userSchema = new Schema({
      name: {
        type: String,
        required: true
      },
      lectures: [lectureSchema]
    });
    
    var User = mongoose.model( "User", userSchema );
    
    function logger(data) {
      return JSON.stringify(data, undefined, 2);
    }
    
    async.waterfall(
      [
        function(callback) {
          User.remove({},function(err) {
            callback(err);
          });
        },
        function(callback) {
          console.log("here");
          var user = new User({ "name": "bob" });
          user.save(function(err,user) {
            callback(err,user);
          });
        },
        function(user,callback) {
          console.log("Saved: %s", logger(user));
          User.findByIdAndUpdate(
            user._id,
            {
              "$addToSet": {
                "lectures": {
                  "subject": "physics",
                  "topic": "Fluid Mechanics",
                  "day": "Monday",
                  "faculty": "Nancy Wagner"
                }
              }
            },
            { "new": true },
            function(err,user) {
              callback(err,user);
            }
          );
        }
      ],
      function(err,user) {
        if (err) throw err;
        console.log("Modified: %s", logger(user));
        mongoose.disconnect();
      }
    );
    

    输出:

    Mongoose: users.remove({}) {}
    here
    Mongoose: users.insert({ name: 'bob', _id: ObjectId("55cda4dc40f2a8fb0e5cdf8b"), lectures: [], __v: 0 })
    Saved: {
      "__v": 0,
      "name": "bob",
      "_id": "55cda4dc40f2a8fb0e5cdf8b",
      "lectures": []
    }
    Mongoose: users.findAndModify({ _id: ObjectId("55cda4dc40f2a8fb0e5cdf8b") }) [] { '$addToSet': { lectures: { faculty: 'Nancy Wagner', day: 'Monday', topic: 'Fluid Mechanics', subject: 'physics', _id: ObjectId("55cda4dc40f2a8fb0e5cdf8c") } } } { new: true, upsert: false, remove: false }
    Modified: {
      "_id": "55cda4dc40f2a8fb0e5cdf8b",
      "name": "bob",
      "__v": 0,
      "lectures": [
        {
          "faculty": "Nancy Wagner",
          "day": "Monday",
          "topic": "Fluid Mechanics",
          "subject": "physics",
          "_id": "55cda4dc40f2a8fb0e5cdf8c"
        }
      ]
    }
    

    这样工作正常,你不需要挖掘原生方法只是为了让它工作 .

    数组的属性使查询和过滤非常容易,以及跨数据的“聚合”信息,对于所有这些信息,MongoDB都喜欢引用所有信息的“严格路径” . 否则,您只是“特定键”,并且在不提及每个可能的“键组合”的情况下,无法对其进行索引或搜索 .

    像这样的属性是一个更好的方法 . 这里没有错误 .

  • 2

    Mongoose失去了自动检测并保存对Mixed类型所做更改的功能,因此您需要通过调用文档的 .markModified(path) 方法来更改混合类型的值,该方法将路径传递给您刚刚更改的Mixed类型:

    doc.mixed.type = 'changed';
    doc.markModified('mixed.type');
    doc.save() // changes to mixed.type are now persisted
    

    在您的情况下,您可以使用 findById() 方法通过调用主题数组上的 addToSet() 方法进行更改,然后触发 save() 方法来保留更改:

    userModel.findById(user._id, function (err, doc){
        var item = {
            "name": "Fluid Mechanics",
            "day": "Monday",
            "faculty": "Nancy Wagner"
        };
        doc.lectures.physics.topic.addToSet(item);
        doc.markModified('lectures');
        doc.save() // changes to lectures are now persisted 
    });
    

相关问题