【问题标题】:Using Model.create() and save() inside for loop在 for 循环中使用 Model.create() 和 save()
【发布时间】:2017-11-15 07:49:18
【问题描述】:

嘿,我对 Javascript 和 Node 还很陌生,但我遇到了一个困扰我一段时间的问题。

我有一个 User 模型和一个 Image 模型,我正在使用 Multer 上传一组图像,尝试遍历这个数组,为每个模型创建一个新的 Image 模型,然后取消移动该 Image进入我用户的照片。我已将 Multer 设置为成功填充 req.files。这是代码。

router.post("/users/:user/photos/upload", middle.isLoggedIn, upload.array("photos", 4), function(req, res) {
    User.findById(req.params.user, function(err, foundUser) {
        for(var i = 0, len = req.files.length; i < len; i++) {
            Image.create(req.files[i], function(err, newImage) {
                if(err) {
                    return console.log(err.message);
                }
                newImage.human = foundUser;
                newImage.save();
                console.log(newImage);
                foundUser.photos.unshift(newImage);
                foundUser.save();
            });
        }
        console.log(foundUser);
    });
});

console.log(foundUser); 似乎在console.log(newImage); 之前执行和打印

用户模型

var mongoose                = require("mongoose"),
    passportLocalMongoose   = require("passport-local-mongoose");

var UserSchema = new mongoose.Schema({
    username: String,
    password: String,
    firstName: String,
    lastName: String,
    city: String,
    photos: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: "Image"
        }    
    ]
});

HumanSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);

图像模型

var mongoose            = require("mongoose");

var ImageSchema = new mongoose.Schema({
    fieldname: String,
    originalname: String,
    mimetype: String,
    filename: String,
    destination: String,
    size: Number,
    path: String,
    human: {
        id: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "Human"
        }
    }
});

module.exports = mongoose.model("Image", ImageSchema);

这是我的第一个 stackoverflow 问题,如果我没有发布足够的代码,请告诉我。

我认为这与 Image.create() 是异步的有关,我仍在尝试了解有关此和承诺的更多信息,但我仍然不完全理解它与我的代码的相关性。

【问题讨论】:

  • 我看不到您的代码 console.log(req.user); 出现在哪里。你的意思是console.log(foundUser);
  • 是的@dave 抱歉,已编辑原帖

标签: javascript node.js mongodb mongoose mongoose-schema


【解决方案1】:

使用Mongoose's promise support

Promise.all 允许您解决一系列承诺。

async/await Promises 的控制流。

我不确定您的结构化代码是否可以在没有串行循环的情况下工作,因为异步代码可以按任何顺序执行。我不确定在不同时间在同一个对象上触发多个foundUser.save()s 会不会很好。将数据库对象长时间保存在内存中也会引发更多的并发数据问题。

Bluebird promise 库包括一些额外的帮助器,例如 Promise.each,它将在下一次开始之前连续完成承诺,这可能在这里有用。

const Promise = require('bluebird')

router.post("/users/:user/photos/upload", middle.isLoggedIn, upload.array("photos", 4), async function(req, res, next) {
    try {
        let foundUser = await User.findById(req.params.user)
        await Promise.each(req.files, async file => {
            let newImage = await Image.create(file)
            newImage.human = foundUser;
            await newImage.save()
            console.log(newImage)
            foundUser.photos.unshift(newImage)
            await foundUser.save()
        }
        console.log(foundUser)
    }
    catch (err) {
        next(err)
    }
})

.map.reduce 等其他方法有助于使使用 Promise 的标准数组/循环类型操作更容易执行。

原子更新

关于并发问题,您可以在 MongoDB 中进行的任何“原子”更新都是一件好事。因此,您无需选择某些内容,在 JS 中对其进行修改,然后将其保存回来,而是将更新发送到 Mongo 并让 db 服务器处理它。无论您将更新发送到数据库的顺序如何,它们都将始终更新最新的数据副本。

在这种情况下,数组unshift可以在没有初始选择的情况下通过使用findByIdAndUpdate$push完成(可以在位置0推送,在mongo中没有$unshift)。

如果您向您的用户模型添加方法以添加照片:

addPhoto(user_id, newImage){
    return User.findByIdAndUpdate(
        user_id,
        { $push: { photos: { $each: [newImage], $position: 0 } } } }
        { safe: true, new: true }
    )
}

所以代码看起来像

const Promise = require('bluebird')

router.post("/users/:user/photos/upload", middle.isLoggedIn, upload.array("photos", 4), async function(req, res, next) {
    try {
        let foundUser = await User.findById(req.params.user)
        if (!foundUser) throw new Error(`No user found: $user`)
        let results = await Promise.map(req.files, async file => {
            let newImage = await Image.create(file)
            newImage.human = foundUser
            await newImage.save()
            console.log(newImage)
            let user_update = await User.addPhoto(req.params.user, newImage)
            console.log(user_update)
        }
    }
    catch (err) {
        next(err)
    }
})

【讨论】:

    猜你喜欢
    • 2019-04-27
    • 1970-01-01
    • 2020-12-07
    • 2019-03-14
    • 2018-09-13
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多