如何在对象数组中使用 localField 进行猫鼬填充虚拟

问题描述 投票:0回答:1

我正在尝试使用 mongoose 自动用另一个模型填充一个模型。 遵循此官方文档:https://mongoosejs.com/docs/populate.html

我无法使用标准引用:“ModelName”,因为只有当您使用 _id 字段作为关系字段时,它才有效...并且我有自己的关系链接字段,例如“itemId”和“subItemIs”,并且我无法使用“_id”字段

因此,我使用名为 Populate Virtuals 的子功能(此处的官方文档:https://mongoosejs.com/docs/populate.html#populate-virtuals

虽然我可以使该功能在某些建模案例中完美工作......我拥有的特定模型案例是唯一一个我无法使其发挥作用的案例。

这是“一张图片胜过千言万语”的情况之一,因此与其描述问题,不如简单地阅读一个数据+代码片段,该片段公开了何时工作以及何时失败

我实际上创建了一个不言自明的孤立数据+代码,它完全描述了实现预期目标的需求和失败:

猫鼬版本:8.1.1 Node.js 版本:20.5.0 MongoDB服务器版本:7.0.4 Typescript 版本:未使用

// Mongo Data:
//
// Collection: units
// { unitId: 'in', label: 'Inches' }
// { unitId: 'ft', label: 'Feet' }
// { unitId: 'yr', label: 'Yard' }
//
// Collection: reports:
// {
//   reportId: 'r1',
//   singleMeasurement:
//     { value: '1', unitId: 'in' },
//   multipleMeasurements: [
//     { value: '2', unitId: 'ft' },
//     { value: '3', unitId: 'yr' }
//   ]
// }

import mongoose from 'mongoose'

const unitSchema = new mongoose.Schema({
  unitId: { type: String },
  label: { type: String }
})

const reportSchema = new mongoose.Schema({
  reportId: { type: String },
  singleMeasurement: {
    value: { type: Number },
    unitId: { type: String } // This WORKS to assist creating 'unit' attribute in 'singleMeasurement' obj
  },
  multipleMeasurements: [{
    value: { type: Number },
    unitId: { type: String } // This FAILS to assist creating 'unit' attribute in 'multipleMeasurements' obj array
  }]
})

reportSchema.virtual('singleMeasurement.unit', { ref: 'Unit', localField: 'singleMeasurement.unitId', foreignField: 'unitId' })
reportSchema.virtual('multipleMeasurements.unit', { ref: 'Unit', localField: 'multipleMeasurements.unitId', foreignField: 'unitId' })

reportSchema.set('toJSON', { virtuals: true })
reportSchema.set('toObject', { virtuals: true })

// // // // // // // // // // // // // // //

const reportModel = mongoose.model('Report', reportSchema, 'reports')
const unitModel = mongoose.model('Unit', unitSchema, 'units')

// // // // // // // // // // // // // // //

await mongoose.connect('mongodb://username:password@localhost:27017/database')

const report = await reportModel.findOne({ reportId: 'r1' })

await report.populate('singleMeasurement.unit')
await report.populate('multipleMeasurements.unit')

console.log('\n\n singleMeasurement: ' + report.singleMeasurement.toString())
// this WORKS; by including singleMeasurement.unit

console.log('\n\n multipleMeasurements: ' + report.multipleMeasurements.toString())
// this FAILS; by missing multipleMeasurements.unit

这些是预期结果和假设:

// report.singleMeasurement.unit      => Expected: Object => Received: Object      => OK
// report.multipleMeasurements[].unit => Expected: Object => Received: undefined   => FAIL

我还尝试将 localField 更改为“multipleMeasurements.$*.unitId”,这是支持在地图内填充所需的语法......但它也不起作用。

是否可能还有另一种类似于该语法的语法,但对于我无法理解的数组?

mongoose mongoose-populate
1个回答
0
投票

执行此操作的最佳方法是创建一个

multipleMeasurement
模式并在该模式上注册虚拟。然后,您可以使用该架构作为
multipleMeasurements
数组的类型。这是一个例子:

  1. 创建一个单独的
    multipleMeasurementSchema
const multipleMeasurementSchema = new mongoose.Schema({
    value: {
        type: Number
    },
    unitId: {
        type: String
    }
}, {
    toJSON: {
        virtuals: true
    },
    toObject: {
        virtuals: true
    }
});
  1. multipleMeasurementSchema
  2. 上注册虚拟
multipleMeasurementSchema.virtual('unit', { ref: 'Unit', localField: 'unitId', foreignField: 'unitId' });
  1. multipleMeasurementSchema
    设置为
    multipleMeasurements
    数组类型
const reportSchema = new mongoose.Schema({
    reportId: { type: String },
    singleMeasurement: {
        value: { type: Number },
        unitId: { type: String }
    },
    multipleMeasurements: [multipleMeasurementSchema]
})
  1. 照常在
    singleMeasurement.unit
    上注册虚拟
reportSchema.virtual('singleMeasurement.unit', { ref: 'Unit', localField: 'singleMeasurement.unitId', foreignField: 'unitId' });
reportSchema.set('toJSON', { virtuals: true })
reportSchema.set('toObject', { virtuals: true })
  1. 现在当你
    populate
const report = await reportModel.findOne({ reportId: 'r1' })
.populate('singleMeasurement.unit')
.populate('multipleMeasurements.unit')
© www.soinside.com 2019 - 2024. All rights reserved.