【问题标题】:mongoose - get a nested array of objects from Model.find() and manipulate the inner arraymongoose - 从 Model.find() 获取嵌套的对象数组并操作内部数组
【发布时间】:2021-11-04 13:28:06
【问题描述】:

我正在尝试从我的服务器路由内的数据库中获取具有特定 ID 的对象数组,然后在数组内添加更改对象的属性(而不是将 objectID 返回给我想要的客户端将 Document 作为具有特定 ID 的对象返回)。

这是我的代码:

        let orders = await Order.find({restaurant: restaurantID, status: 'PROCESSING'})

        for(let order of orders){   //iterate through all orders
            for(let element of order.dishes){     //iterate through order.dishes array (called 'element' since the array contains objects)
                let dish = await Dish.findOne({_id: element._id})
                element['dish'] = dish  //create new property for the dish object
                delete element._id      //remove the ID property since it already exists inside the element.dish object
            }
        }

orders 中的每个order 对象都包含一个名为dishes 的数组,其中包含具有amountid 属性的对象。由于我的前端不能对 ID 做太多事情,所以我想删除 id 属性并添加一个名为 disc 的新属性,其中包含 id 指向的盘对象。

我面临的问题是我不知道如何操作orders 数组内容。每当我将orders 解析为 JSON 并将其发送到我的响应中时,我都会收到我想要的订单对象的 JSON 数组。但是当我添加上面粘贴的代码时,它不会改变我的订单中的任何内容。

每当我在 for 循环中记录元素时,它看起来像这样:EmbeddedDocument {__parentArray: Proxy, __index: 0, $__parent: model, $__: InternalCache, $isNew: false, …} 但是当我将它解析为 JSON 时,我得到了我想要的,即:{"amount":1,"_id":"6183b84fec1c3e109a2271be"}

orders 在这种情况下甚至是一个数组吗?如果不是,那么操作它/将文档作为数组获取的最简单方法是什么?

这是我在调试窗口中查看订单时的样子:

price (get):ƒ () {\n        return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n      }
price (set):ƒ (v) {\n        this.$set.call(this.$__[scopeSymbol] || this, path, v);\n      }
restaurant (get):ƒ () {\n        return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n      }
restaurant (set):ƒ (v) {\n        this.$set.call(this.$__[scopeSymbol] || this, path, v);\n      }
status (get):ƒ () {\n        return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n      }
status (set):ƒ (v) {\n        this.$set.call(this.$__[scopeSymbol] || this, path, v);\n      }
timestamp (get):ƒ () {\n        return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n      }
timestamp (set):ƒ (v) {\n        this.$set.call(this.$__[scopeSymbol] || this, path, v);\n      }
user (get):ƒ () {\n        return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n      }
user (set):ƒ (v) {\n        this.$set.call(this.$__[scopeSymbol] || this, path, v);\n      }
__v (get):ƒ () {\n        return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n      }
__v (set):ƒ (v) {\n        this.$set.call(this.$__[scopeSymbol] || this, path, v);\n      }
__proto__:Model
length:1

在邮递员中, res.body 看起来像这样(几乎完全像它应该的那样,但它只包含 id 而不是菜对象):

[
    {
        "_id": "6183b84fec1c3e109a2271bd",
        "user": "6166bc426181646198fc483c",
        "restaurant": "6176947ce8b10986b018930e",
        "dishes": [
            {
                "amount": 1,
                "_id": "6183b84fec1c3e109a2271be"
            },
            {
                "amount": 2,
                "_id": "6183b84fec1c3e109a2271bf"
            }
        ],
        "price": 30,
        "status": "PROCESSING",
        "timestamp": "2021-11-04T10:39:11.800Z",
        "__v": 0
    }
]

如果这已经解决,请给我发送问题/答案的链接。我花了最后几个小时试图解决这个问题,我已经看了很多问题,但没有一个答案对我有帮助

【问题讨论】:

  • 您想要做的是通常的要求,因此本机支持。前提是你的订单模型设置好让mongodb知道dishes是一个Dish文档引用的数组,你就可以自动让mongodb.populate()这个dish数组。有关基本示例,请参阅 here
  • 好的,谢谢。我不知道这件事。如果您愿意,请写一个答案,我会将其标记为已解决
  • 如果文档回答了一个问题,则它不再是对 stackoverflow 的有用补充。这意味着我们不应该发布答案,并且该问题将被标记为删除。 (请注意,如果您在填充查询结果时遇到问题,可以在这里询问,所以如果是这种情况,请务必相应地编辑您的问题!)
  • 好的,谢谢。在这种情况下,我为这个问题道歉,我不知道 populate() 存在,当我寻找关于这个主题的其他 SO 帖子时,我找不到任何人提到它

标签: javascript mongodb express mongoose


【解决方案1】:

这是一个常见的问题。人们经常感到不安,因为他们无法更改来自 MongoDB 的数据。

问题是,Mongoose 有点奇怪;它不返回简单的 JSON,而是构造并返回 Mongoose 对象的集合。这些对象有额外的方法,比如.save(),但最重要的是它们的嵌套对象是不可变的。简单地改变它们的属性是没有效果的。

为了修改Mongoose返回的数据,你有两种可能:

  1. 使用.markModified()

这是一个非常奇怪的概念,但您所做的更改只有在您将它们标记为已修改后才会应用。例如:

element['dish'] = dish;
order.save();

这不会有任何影响。 Mongo 中的名称将保持不变。你需要.markModified()

element['dish'] = dish;
order.markModified("dishes");
order.save(); // Works now :|
  1. 告诉 Mongoose 返回简单的 JSON

您可以使用.lean() 阻止 Mongoose 构造自己的对象。这将返回可以随意篡改的简单 JSON 数据。

let orders = await Order
           .find({restaurant: restaurantID, status: 'PROCESSING'})
           .lean()
           .exec(); // Also add .exec(), it returns a true Promise and not a thenable 

奖励:lean() 更快更轻。

【讨论】:

  • 我认为这不是 OP 真正想要的。 OP 正在尝试更改返回的数据,但这仅仅是因为他们不知道 populate()。 OP 尝试做的事情比假设的要简单得多,并且不需要您的答案中概述的任何方法。
  • 是的,你是对的。我尝试用谷歌搜索,但 populate() 从未在任何答案中提及
  • @ChrisG 哦,确实。不错的收获。你是对的,.populate('dishes') 做得更好!但你不得不承认,这仍然是一个很好的 Mongoose 教程 :)
猜你喜欢
  • 2019-08-09
  • 1970-01-01
  • 2023-04-04
  • 2022-01-11
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
相关资源
最近更新 更多