Mongoose 删除文档引用

3

我有两个模式。一个是用户模式,另一个是项目模式。用户模式中保存了对项目模式的引用。

const UserSchema = new Schema({
    username: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    date: {
        type: Date,
        default: Date.now
    },
    projects: [
        {
            type: Schema.Types.ObjectId,
            ref: 'Project'
        }
    ]
});

项目架构:
const projectSchema = new Schema({
    experience: [
        {
            company: String,
            positionExperience: String,
            descriptionExperience: String,
            websiteExperience: String,
            timeperiodExperience: Array,
        }
    ],
    education: [
        {
            school: String,
            degree: String,
            descriptionEducation: String,
            websiteEducation: String,
            timeperiodEducation: Array
        },
    ],
}, {
        collection: 'project'
    });

当当前登录的用户保存一个项目时,它会通过以下代码推入用户模式中的项目数组中: user.projects.push(project);

我有一个删除路由可以让用户删除项目:

router.delete('/delete/:id', passport.authenticate('jwt', { session: false }), (req, res, next) => {
    Project.findByIdAndRemove({ _id: req.params.id }, (err) => {
        if (err) res.json(err)
        else res.json('Succesfully removed')
    });
})

然而,在数据库中,当前登录用户的集合中未删除项目ID。数据库日志如下:
"_id" : ObjectId("5d9474c2dccfb181dd8e9fde"),
    "projects" : [
        ObjectId("5d9474cddccfb181dd8e9fdf"),
        ObjectId("5d94753e9b610a81f83937e9"),
        ObjectId("5d947602f72f0f820f2974f0"),
        ObjectId("5d947ae435d2e982535d9a53"),
    ],
    "username" : "b",
    "password" : "$2a$10$4T1TjmFYD/01wEdMbiSRMeKNVKegnkVBOGGHasP.qJjVbQzmgEZDO",
    "email" : "b",

所有的项目都已经被删除,但是它们的ID仍然存在于用户记录中。我需要某种垃圾回收机制来将它们也删除。我看了一下级联删除。级联删除意味着如果父表中的记录被删除,则对应的子表中的记录将自动删除。在我的情况下,用户是父表,我不想删除用户,而是要删除与用户相关联的项目。我尝试过像这样的方法:

User.findOne({ username: req.user.username }, (err, user) => {
    Project.remove({
        "_id": {
            $in: user.projects
        }
    }, function(err) {
        if(err) return next(err);
        user.deleteOne()
    })
})

但这会删除整个用户...我该如何同时从项目集合和与已登录用户相关的项目中删除一个项目?

* ----- 编辑 ----- *

经过进一步的挖掘,感谢非常有用的答案,这就是我想出来的:

//delete route
router.delete('/delete/:id', passport.authenticate('jwt', { session: false }), (req, res, next) => {
    User.findOneAndUpdate({ username: req.user.username }, {
        $pull: {
            'projects': req.params.id
        }
    }, function (err, model) {
        if (!err) {
            Project.findByIdAndRemove({ _id: req.params.id }, (err) => {
                if (err) res.json(err)
                else res.json('Succesfully removed')
            });
        }
        else {
            res.status(500).json(err)
        }
    });
})

2
不要使用 deleteOne(),而是使用 update()$pull,并从用户对象中删除 projectId。 - Mohammed Amir Ansari
@MohammedAmirAnsari 感谢您的评论,我确实使用了 $pull 从用户集合中获取它。我已经将我的代码添加到了我的问题上方。 - Reinier68
很好,希望有所帮助 :) - Mohammed Amir Ansari
2个回答

1
您需要编写自己的删除函数。请查看这个问题,其中已经处理了这个问题。

嘿,感谢您的评论,因为它我已经让我的代码可行了。我已经将它添加到了我的问题上面,不介意看一下吗? - Reinier68
你的解决方案应该可以正常工作。你不使用链接问题中的预删除钩子,有什么原因吗?在我看来,这样会更好。 - Pastafari

0
User.findOneAndUpdate({ username: req.user.username }, { $set : { projects : [] 
   } }, (err, user) => {
     Project.remove({
        "_id": {
        $in: user.projects
     }
  }, function(err) {
    if(err) return next(err);
    user.deleteOne()
  })
})

这样做就可以了,findOneAndUpdate将返回原始文档而不是更新后的文档。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接