【问题标题】:How to remove properties of mongo objects in an array?如何删除数组中 mongo 对象的属性?
【发布时间】:2020-09-07 03:55:10
【问题描述】:

我希望下面的 sn-ps 能让我的问题更清楚。我可以获取一个嵌入了类别对象数组的对象。从类别对象中,我只想显示某些属性。

这就是我现在得到的:

{
  "photo": [],
  "_id": "5ec55ae39eere8ert85bf8fe749",
  "title": "Blog about coding",
  "description": "Hi, I want to share with you my incredible journey as a software developer...",
  "rate": 3,
  "category": [
    {
      "_id": "5ec55ae39aaa78985f8fe74a",
      "name": "programming",
      "display_name": "Programming"
    }
  ],
  "createdAt": "2020-05-20T16:29:23.982Z",
  "updatedAt": "2020-05-20T16:29:23.982Z",
  "__v": 0
}

使用以下代码:

/* GET blog with id */
router.get("/:id", async (req, res, next) => {
    try {
        const blog = await Blog.findById(req.params.id); // How to filter out fields of objects in category array?
        res.send(blog);
    } catch(ex) {
        res.status(400).send(ex); 
    }
});

这是我真正想要的:

{
  "photo": [],
  "_id": "5ec55ae39eere8ert85bf8fe749",
  "title": "Blog about coding",
  "description": "Hi, I want to share with you my incredible journey as a software developer...",
  "rate": 3,
  "category": [
    {
      "display_name": "Programming"
    }
  ],
  "createdAt": "2020-05-20T16:29:23.982Z",
  "updatedAt": "2020-05-20T16:29:23.982Z",
  "__v": 0
}

所以,在类别中我只想要“display_name”

我怎样才能得到这个。我以为我以前看到过解决方案,但现在找不到了。

【问题讨论】:

    标签: node.js mongodb express mongoose mongodb-query


    【解决方案1】:

    您还可以为您的博客集合创建一个架构,然后自定义 toJSON 方法来删​​除您想要隐藏的属性,如下所示:

    BlogSchema.methods.toJSON = function callback() {
    
      const blog = this;
      const blogObject = blog.toObject();
    
      delete blogObject._id;
      delete blogObject.name;
    
      return blogObject;
    };
    

    我使用这种方法在向用户发送信息时隐藏密码等敏感数据!

    【讨论】:

    • 您当然可以在代码中执行此操作,但更好的部分是在从数据库中提取数据时排除不必要的字段(如果不需要,为什么要通过网络获取所有字段),排除有很大帮助在处理庞大的数据集时,需要迭代/检索/处理的数据更少,为我们带来了更多的性能优势 :-)
    • 你是对的!我只是从 node 和 mongo 开始,还有很多事情我还不知道如何正确地做。只是想也许这可能会帮助像我这样的其他新手。感谢您的评论和回答,他们帮助了我很多! :)
    【解决方案2】:

    由于您使用的是 .findById(),它是 .findOne({_id: ObjectId()}) 的 mongoose 包装器,它减轻了将输入字符串转换为 ObjectId() 的负担,但是 .find() 对投影没有什么帮助,您需要列出所有字段如下所示:

    /** .findById(inputString, projection) */
    
    Blog.findById(req.params.id,
    {
      "category.display_name": 1,
      "title": 1,
      "description": 1,
      "rate": 1,
      "createdAt": 1,
      "updatedAt": 1
    })
    
    /** Or */
    
    Blog.findById(req.params.id,
    {
      "category._id": 0,
      "category.name": 0,
    })
    

    测试:因为操场不能使用.findById 使用.find() 测试它:mongoplayground

    但如果你倾向于使用aggregation,你可以在投影中做更多的事情:

    const mongoose = require('mongoose');
    
    /* GET blog with id */
    router.get("/:id", async (req, res, next) => {
        try {
            const blog = await Blog.aggregate([{$match : {_id : mongoose.Types.ObjectId(req.params.id)}},
                { $addFields: { category: { $map: { input: "$category", in: { display_name: "$$this.display_name" } } } } }
            ]);
            res.send(blog);
        } catch(ex) {
            res.status(400).send(ex); 
        }
    });
    

    测试: mongoplayground

    注意:此聚合查询遍历category 数组并在每个对象中仅保留display_name,仅当您需要排除category 对象中的大量字段时才使用此管道。我建议在.findById() 中使用第二个选项,因为您无需将string 转换为ObjectId() 和聚合管道,只是为了排除类别数组对象内的字段name_id

    【讨论】:

    • 聚合的部分在哪里? :P 谢谢我的朋友,你真的帮助了我。
    • @AndaluZ : 更新了也许你试一试并检查差异并选择更好的:-)
    • 谢谢关于聚合方法的解释。是的,排除 .findById() 中的属性是我现在最简单的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2021-01-30
    • 1970-01-01
    • 2021-09-29
    • 2016-09-10
    • 2021-06-18
    • 2021-02-24
    • 2018-07-01
    • 1970-01-01
    相关资源
    最近更新 更多