首页 > 解决方案 > Mongoose 通过包含子数组的参数查找

问题描述

我正在创建一个应用程序,其中创建了一个作业并将该作业的 id 添加到另一个集合(客户端)中,以便可以从客户端本身引用该作业。到目前为止,我已经能够将作业的 ID 添加到客户的集合中,但是如果作业被删除,我无法弄清楚如何从客户的集合中删除作业的 ID。这是因为 id 作为子集合存储在客户端中。我试图开始工作的代码如下:

// delete
app.delete("/jobs/:id", function(req, res){ 

            Client.find({jobs._id: req.params.id}, function (err, foundClient){  //This part doesn't work
                if (err) {
                    console.log(err);
                } else {
                    // Add id identifier to Client
                    foundClient.jobs.pull(req.params.id);
                    foundClient.save();
                }
            }); 
//  Delete Job
    Job.findByIdAndRemove(req.params.id, function(err, deletedJob){
        if (err){
            console.log(err)
        } else {            
            //  Redirect
            res.redirect("/jobs");
        }
    });
});

我试图让这部分的逻辑起作用:

Client.find({jobs._id: req.params.id}, 

这是客户端架构

// =======================Client Schema

var clientSchema = new mongoose.Schema({
    organization_name: String,
    first_name: String,
    middle_name: String,
    last_name: String,
    email_address: String,
    phone_number: String,
    street: String,
    city: String,
    state: String,
    zip: String,
    description: String,
    active: {type: Boolean, deafult: true},
    date_added: {type: Date, default: Date.now},
    transactions: [{type: mongoose.Schema.Types.ObjectID, ref: "Transaction"}],
    jobs: [{type: mongoose.Schema.Types.ObjectID, ref: "Job"}]
});

module.exports = mongoose.model("Client", clientSchema);

基本上,我试图告诉它做的是找到客户端,其中客户端的作业数组包含的 id 等于被删除作业的 id。当然,这种语法是不正确的,所以它不起作用。我无法找到解释我将如何做到这一点的文档。有没有更直接的方法来做到这一点,就像我在这里写出来的那样?我知道如果作业本身不是数组并且只包含一个奇异变量,我可以通过这种方式查询数据库。有没有办法做到这一点,还是我需要编写一个完全独立的循环函数来让它工作?谢谢你。

标签: javascriptnode.jsmongodbmongoose

解决方案


jobs 是一个 id 数组,因此要在 Client 集合中查找req.params.idjobs 数组中的一些文档,查询应该是这样的

Client.find({jobs: req.params.id})

这将返回一个文档数组,每个文档都有一个作业 ID 数组

如果您确定 req.params.id 仅存在于一个文档中,您可以使用 findOne 而不是 find,这将只返回一个包含作业 ID 数组的文档

这是关于find部分

关于从作业数组中删除作业 ID,我们可以使用以下方法之一

1-正如您所建议的,我们可以先找到具有此作业 ID 的客户文档,然后从所有匹配文档中的所有作业数组中删除此 ID

像这样

Client.find({ jobs: req.params.id }, async function (err, foundClients) {
    if (err) {
        console.log(err);
    } else {
        // loop over the foundClients array then update the jobs array

        for (let i = 0; i < foundClients.length; i++) {
            // filter the jobs array in each client 

            foundClients[i].jobs = foundClients[i].jobs || []; // double check the jobs array

            foundClients[i].jobs = foundClients[i].jobs.filter(jobId => jobId.toString() !== req.params.id.toString());
            // return all the jobs Ids that not equal to req.params.id
            // convert both jobId and req.params.id to string for full matching (type and value)

            await foundClients[i].save(); // save the document
        }

    }
});

2-我们可以使用$pull数组更新运算符直接更新作业数组

像这样的东西

Client.updateMany(
    { jobs: req.params.id }, // filter part
    {
        $pull: { jobs: { $in: [req.params.id] } } // update part
    },
    function (err) {
        if (err) {
            console.log(err);
        } else {
            console.log('job id removed from client documents successfully');
        }
    }
);

希望能帮助到你


推荐阅读