猫鼬在 populate() 方法后返回空数组

Mongoose returning empty array after populate() method

过去 3-4 小时我一直在用头撞墙,并在 Whosebug 上查看了无数文章,但无法得到正确填充数组的响应。将 Express.js 与 Typescript、MongoDB 和猫鼬一起使用。问题是当我收到所有订单的响应时,我的 orderedlines 数组是空的,即使我可以检查并看到 MongoDB atlas 中的 ID。这是实际响应:

[
  {
    "orderedlines": [],
    "_id": "6251c61f7385c349f88fe95a",
    "userId": {
      "favourites": [
        "623b39e684b9baf1109053f8",
        "623b3afada0e7828602c78df",
        "623b3b49da0e7828602c78e7",
        "623b39ba84b9baf1109053f7",
        "623b3b59da0e7828602c78e9"
      ],
      "_id": "62326179b9c85d3fc833d686",
      "orders": [],
      "email": "testche_emailche@gmail.com",
      "username": "stef1222",
      "password": "be5Y/IoyrcJHH3ud6Mn/I.8PfBm2JrEKHwYRd8cQwUaAdz.YkKSMa",
      "firstName": "Stefan",
      "lastName": "Georgiev",
      "image": "https://res.cloudinary.com/dtggdx3hc/image/upload/v1648046254/deqr4chfysogoppafdug.png",
      "isAdmin": false,
      "hasWriteAccess": false,
      "__v": 0
    },
    "totalPrice": 121.99,
    "__v": 0
  }
]

如上所示,我的 userId 已成功填充其所有属性,但 orderedlines 无法填充,它作为空数组返回。如果我删除 .populate() 它 returns 带有 ids

的对象数组

我假设出现问题的 orderServices 中的 findOrdersForUserId 函数

const findOrdersForUserId = async (
  userId: string
): Promise<OrderDocument[]> => {
  const ordersToReturn = await Order.find({ userId: userId })
    .sort({ _id: 1 })
    .populate('userId')
    .populate({path:'orderedlines', model:OrderLine})
  return ordersToReturn
}

这是我的订单模型:

import mongoose, { Document } from 'mongoose'

export type OrderLine = {
  orderlineId: string
}

export type OrderDocument = Document & {
  userId: string
  orderedlines: OrderLine[]
  totalPrice: number
}

const orderSchema = new mongoose.Schema({
  userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  totalPrice: Number,
  orderedlines: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'OrderLine',
    },
  ],
})

export default mongoose.model<OrderDocument>('Order', orderSchema, 'orders')

我的 OrderLine 模型:

import mongoose, { Document } from 'mongoose'

export type OrderLineDocument = Document & {
  productId: string
  userId: string
  quantity: number
  price: number
}

const orderLineSchema = new mongoose.Schema({
  quantity: { type: Number, default: 1 },
  price: Number,
  productId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Product',
    required: true,
  },
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true,
  },
})

export default mongoose.model<OrderLineDocument>('OrderLine', orderLineSchema, 'orderlines')

Mongoose version used: mongoose@5.13.10
Node version: v16.13.0
Mongo Shell version: v5.0.6
Express version: express@4.17.1

我会列出一些我尝试解决问题但没有成功的文章:

  1. Mongoose populate() returning empty array
  2. Mongoose populate does not populate array
  3. Mongoose populate not populating an array and always returns an empty array

编辑:所有代码都是来自设置为私有的回购的分支的一部分。我不确定如何将 access/link 分享到分支以便更好地预览代码。如果您想查看其他内容或代码的更具体部分,请赐教。

您这样定义 OrderLine

export type OrderLine = {
  orderlineId: string
}

然后,您将 orderedlines 指定为 OrderLine:

的数组
orderedlines: OrderLine[]

在您的用例中,orderedlinesObjectId 的数组,而不是嵌套 属性 orderlineId 的对象数组。 TypeScript 可能会在定义模型时进行某种转换。

尝试将 orderedlines 更改为 ObjectId 的数组,然后再试一次?

回答我自己的问题,因为我为此苦苦挣扎并希望帮助未来的人阅读这个问题。 首先,真正重要的问题可能是您是否没有指定 collection 名称。为了指定一个 collection 名称,在您的模型创建中添加第三个参数,如下所示:

export default mongoose.model<OrderLineDocument>('OrderLine',orderLineSchema,'orderLines')

在第三个参数之前,mongoose 创建了一个 collection 名称,其中包含 lower-cased 多元化 模型名称 - orderlines。但是当我试图填充我的回复时,我指的是带有大写字母 L 的 orderLines。所以请注意,请始终指定您的 collection 名称 检查您的 collection 名称在你的 MongoDB Shell/ MongoDB Atlas.

其次。始终检查您要填充的 array/object _id 是否 正确 _id 存在于您的 database 中。如果它们是 non-existent 或错误,则响应将包含空数组甚至 return 错误。

例如,当错误发生时我在一开始就添加了这个,但是那些_id不存在(我之前删除了它们但忘记了)首先在我的orderLines collection中(你仍然可以如果它们是正确的 _id 结构,请添加不存在的 _id,因此请注意)

POST http://localhost:5000/api/v1/orders/62326179b9c85d3fc833d686
Content-Type: application/json

{
  "orderedlines":[
      {"_id": "6251be4d4186c34788e4f034"},
      {"_id": "6251be494186c34788e4f030"}
  ],
  "totalPrice":"121.99"
}

第三。如果您使用的是 TypeScript,则可以使用三种方法:

  1. 使用你自己的类型
export type OrderLine = {
  _id: string
}

export type OrderDocument = Document & {
  userId: string
  orderedlines: OrderLine[],
  totalPrice: number
}
  1. 表示这将是一个字符串数组
export type OrderDocument = Document & {
  userId: string
  orderedlines: string[],
  totalPrice: number
}
  1. ObjectId 数组
export type OrderDocument = Document & {
  userId: string
  orderedlines: mongoose.Schema.Types.ObjectId[]
  totalPrice: number
}

在考虑了以上三点之后,最终对我有用的是这种方法:

const findOrdersForUserId = async (
  userId: string
): Promise<OrderDocument[]> => {
  const ordersToReturn = await Order.find({ userId: userId })
    .sort({ _id: 1 })
    .populate('userId')
    .populate({
      path: 'orderedlines',
      populate: { path: 'productId', model: 'Product' },
    })
  return ordersToReturn
}

这是我得到的响应的部分,只是为了展示 orderedline、productId 和 userId 都被正确填充了

{
        "quantity": 4, //part of a single orderedline object
        "_id": "6251be494186c34788e4f030", //part of a single orderedline object
        "productId": { // beginning of populated productId
          "_id": "623b3b24da0e7828602c78e3",
          "name": "AMY SS14R - TRICKSTER",
          "image": "https://res.cloudinary.com/dtggdx3hc/image/upload/v1648048425/amy-deluxe-stick-steel-r-ss09r10_1000x1000_bfngtl.jpg",
          "price": 1299,
          "__v": 0
        }, // end of populated productId
        "price": 2.99, //part of a single orderedline object
        "__v": 0 //part of a single orderedline object
      }
    ], // end of the orderedline array of objects
    "_id": "6252bfa8dd00081d7c273e4d", // _id of the order
    "userId": { //beginning of populated userId
      "favourites": [
        "623b39e684b9baf1109053f8",
        "623b3afada0e7828602c78df",
        "623b3b49da0e7828602c78e7",
        "623b39ba84b9baf1109053f7",
        "623b3b59da0e7828602c78e9"
      ],