我有以下两种模式
const CoconutImportSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
farmerId: {
type: Schema.Types.ObjectId,
ref: 'Farmer'
},
settledOn: {
type: Date,
default: null
},
importedOn: {
type: Date,
default: Date.now()
}
},
{ toJSON: { virtuals: true } }
)
const FMoneyTransactionSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
farmerId: {
type: Schema.Types.ObjectId,
ref: 'Farmer'
},
amount: {
type: Number,
required: true
},
date: {
type: Date,
default: Date.now()
},
settledOnImport: {
type: Schema.Types.ObjectId,
ref:'CoconutImport',
default:null
}
})
CoconutImport中的每个交易都可能在Fmonetrasanction中有多个记录。如果FmoneyTransaction中的交易已结算,则导入交易的_id将出现在resolvedOnImport字段中。
我有一个用例,其中我必须获取导入的详细信息,然后必须从集合FmoneyTransaction中获取所有未结算的交易,即,settedOnImport = null。我还必须在导入中弹出农夫详细信息
await CoconutImports.aggregate([
{
$match: {
_id: Types.ObjectId(importId),
userId: Types.ObjectId(userId)
}
},
{
$lookup: {
from: FMoneyTransactions.collection.name,
"let": {
"farmerId": "$farmerId"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$$farmerId",
"$farmerId"
]
},
{
$eq: [
"$settledOnImport", null
]
}
]
}
}
}
],
as: "unsettledMoneyTransactions"
}
},
{
$lookup: {
from: Farmer.collection.name,
localField: 'farmerId',
foreignField: '_id',
as: 'farmerId'
}
},
这有效,但以下内容无效
await CoconutImports.aggregate([
{
$match: {
_id: Types.ObjectId(importId),
userId: Types.ObjectId(userId)
}
},
{
$lookup: {
from: Farmer.collection.name,
localField: 'farmerId',
foreignField: '_id',
as: 'farmerId'
},
{
$lookup: {
from: FMoneyTransactions.collection.name,
"let": {
"farmerId": "$farmerId._id"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$$farmerId",
"$farmerId"
]
},
{
$eq: [
"$settledOnImport", null
]
}
]
}
}
}
],
as: "unsettledMoneyTransactions"
}
}
}])
有人可以解释为什么吗?
答案 0 :(得分:1)
基于提供的CoconutImportSchema
,farmerId
是ObjectId
。在第一个聚合中,您在"farmerId": "$farmerId"
语句中引用了它,然后在管道中使用它来比较它与farmerId
集合中其他FMoneyTransactions
字段的相等性。因此,将 ObjectId与ObjectId 进行比较。而且有效。
在第二个提供的聚合中,您首先在$lookup
模式上运行Farmer
。该$lookup覆盖现有的farmerId
。由于$lookup
总是返回数组,因此在此步骤之后,您将在farmerId
字段下获得一个数组。然后,当您尝试定义"farmerId": "$farmerId._id"
时,它会返回一个数组,因此在该步骤中,您将 ObjectIds数组与 ObjectId 进行比较。因此,您没有任何结果。
要解决此问题,如果您确定farmerId
与$lookup
之间是一对一的关系,则可以在第一个CoconutImports
之后在$ farmer
上运行$ unwind < / p>
await CoconutImports.aggregate([
{
$match: {
_id: Types.ObjectId(importId),
userId: Types.ObjectId(userId)
}
},
{
$lookup: {
from: Farmer.collection.name,
localField: 'farmerId',
foreignField: '_id',
as: 'farmerId'
},
},
{ $unwind: "$farmerId" },
{
$lookup: {
from: FMoneyTransactions.collection.name,
"let": {
"farmerId": "$farmerId._id"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$$farmerId",
"$farmerId"
]
},
{
$eq: [
"$settledOnImport", null
]
}
]
}
}
}
],
as: "unsettledMoneyTransactions"
}
}
}])