猫鼬:在X集合中创建新元素,在Y集合中更新另一个

时间:2019-02-24 11:21:34

标签: node.js mongodb mongoose

我正在尝试开发一个CRUD应用程序,供用户存储,添加,删除和更新配方。它建立在MEVN堆栈上。当我需要向用户展示他们创建了哪些食谱时,我正在尝试基于以下模型创建食谱:

const RecipeSchema = new Schema({
    title: {
        type: String,
        required: [true, 'Title of the recipe is required'],
    },
    category: {
        type: Array,
        required: [true, 'Category is required'],
    },
    description: {
        type: String,
        required: [true, 'Description is required'],
    },
    imgUrl: {
        type: String,
        required: [true, 'Image is required'],
    },
    ingredients: {
        type: Array,
        required: [true, 'Ingredients are required'],
    },
    timeOfPreparation: {
        type: String,
        required: true,
    },
    preparation: {
        type: String,
        required: true,
    },
    sourceName: {
        type: String,
        required: true,
    },
    sourceUrl: {
        type: String,
        required: true,
    },
    author: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
});

const Recipe = mongoose.model('Recipe', RecipeSchema);

module.exports = Recipe;

并基于此同时更新用户模型:

const UserSchema = Schema({
    googleId: String,
    name: String,
    favorites: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' }],
    authoredRecipes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' }],
});

const User = mongoose.model('User', UserSchema);

module.exports = User;

在控制器中,我有此方法(根据@Stock Overflaw注释):

exports.create_new_recipe = (req, res, next) => {
Recipe.create(req.body)
    .then(recipe => {
        User.update(
            { _id: req.body.author },
            {
                $push: { authoredRecipes: recipe.id },
            }
        );
        res.send(res.status);
    })
    .catch(error => {
        res.status(500).json({ error });
    });

};

当我转到/ create端点时,将调用此方法。但是,即使我确实获得了所有正确的ID(req.body.author和recipe.id),也无法使它正常工作。在我的mLab配方集合中,配方可以正确显示(我使用authorId插入的所有数据),但是在用户集合中,authoredRecipes数组保持为空。

如何让猫鼬在一个集合中创建一个对象并根据其ID更新另一个对象?

1 个答案:

答案 0 :(得分:1)

findByIdAndUpdate的{​​{3}}需要_id字段作为其值,而不是对象:

User.findByIdAndUpdate(req.body.author, {
  $push: { authoredRecipes: recipe.id }
});
// equivalent to the more general method:
User.findOneAndUpdate({ _id: req.body.author }, {
  $push: { authoredRecipes: recipe.id }
});
// and if you don't need the modified document in your callback, this should be faster:
// EDIT: this is advised against (we should use a user object, not the collection)
User.update({ _id: req.body.author }, { // or updateOne
  $push: { authoredRecipes: recipe.id }
});

编辑:一个可行的最小示例

也许{new: true}好吗?取决于您测试它是否有效的方式...

const mongoose = require('mongoose');
const fs = require('fs');

const userIdFile = './tmp.txt'; // just for this test

mongoose.connect('mongodb://localhost/meuh', {
  useNewUrlParser: true, // removes a deprecation warning
  useFindAndModify: false // removes another deprecation warning
});

// make schemas/models
const RecipeSchema = mongoose.Schema({
  title: { type: mongoose.Schema.Types.String }
});
const UserSchema = mongoose.Schema({
  name: { type: mongoose.Schema.Types.String },
  data: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' }]
});
const RecipeModel = mongoose.model('Recipe', RecipeSchema);
const UserModel = mongoose.model('User', UserSchema);

// user precreation
// UserModel.create({
//   name: 'me, myself and I'
// }).then((user) => {
//   fs.writeFile(userIdFile, user.id, console.log.bind(null, 'error writing file:'));
//   mongoose.connection.close();
// });
// return;

// fetch user
const userId = fs.readFileSync(userIdFile);

let pushedRecipeId; // to test everything went smooth
RecipeModel.create({
  title: 'pasta solo'
}).then((recipe) => {
  console.log('created recipe:', recipe);
  pushedRecipeId = recipe.id;
  return UserModel.findOneAndUpdate(
    { _id: userId },
    { $push: { data: recipe.id } },
    { new: true } // forces callback to be passed a fresh object
  );
}).then((user) => {
  console.log('updated user:', user);
  console.log('izok:', !!~user.data.indexOf(pushedRecipeId));
  mongoose.connection.close();
}).catch((err) => {
  console.log('error', err);
  mongoose.connection.close();
})

我得到的示例输出:

# creating user (uncommented this part)
ubuntu@ubuntu-VirtualBox:~/web/test$ node .
error writing file: null
# calling for $push (re-commented user creation)
ubuntu@ubuntu-VirtualBox:~/web/test$ node .
created recipe: { _id: 5c72be7032bd2f1acad37c95, title: 'pasta solo', __v: 0 }
updated user: { data: [ 5c72be7032bd2f1acad37c95 ],
  _id: 5c72be6a8143fd1aa9416d85,
  name: 'me, myself and I',
  __v: 0 }
izok: true
# again $push
ubuntu@ubuntu-VirtualBox:~/web/test$ node .
created recipe: { _id: 5c72c020c2ac7a1b8c65fa36, title: 'pasta solo', __v: 0 }
updated user: { data: [ 5c72be7032bd2f1acad37c95, 5c72c020c2ac7a1b8c65fa36 ],
  _id: 5c72be6a8143fd1aa9416d85,
  name: 'me, myself and I',
  __v: 0 }
izok: true
# and again
ubuntu@ubuntu-VirtualBox:~/web/test$ node .
created recipe: { _id: 5c72c023bf62331b97ef096b, title: 'pasta solo', __v: 0 }
updated user: { data: 
   [ 5c72be7032bd2f1acad37c95,
     5c72c020c2ac7a1b8c65fa36,
     5c72c023bf62331b97ef096b ],
  _id: 5c72be6a8143fd1aa9416d85,
  name: 'me, myself and I',
  __v: 0 }
izok: true
# end
ubuntu@ubuntu-VirtualBox:~/web/test$ 

我看不出您的代码有什么问题,但至少您有一些可与之比较的地方……希望这对您有帮助!