You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB嵌套Lookup查询返回空数组,求问题原因与解决方法

问题:MongoDB聚合Lookup查询返回空数组

我有new_users和workspaces两个集合,执行Lookup查询时,userData字段始终返回空数组。

集合实体定义

new_users集合(UserEntity)

export class UserEntity {
    @Prop({ required: false, type: Types.ObjectId, default: () => new ObjectId() })
    _id?: Types.ObjectId;

    @Expose()
    @Prop({ default: '', trim: true, text: true })
    firstName: string;

    @Expose()
    @Prop({ default: '', trim: true, text: true })
    lastName: string;
}

workspaces集合(WorkspaceEntity)

export class WorkspaceUsers {
    @Expose()
    @Prop({ type: () => [WorkspaceUserGroup] })
    groups: WorkspaceUserGroup[];

    @Expose()
    @Prop({ required: true, type: String, enum: WorkspaceRoleEnum })
    workSpaceRole: WorkspaceRoleEnum;

    @Expose()
    @Prop({ required: true, type: String, ref: () => UserEntity })
    userID: string;
}

export class WorkspaceEntity {

    @Prop({ required: false, type: Types.ObjectId, default: () => new ObjectId() })
    _id?: Types.ObjectId;
    
    @Expose()
    @IsString()
    @IsDefined()
    @Prop({ required: true, trim: true })
    name: string;
    

    @Expose()
    @IsOptional()
    @IsArray()
    @ValidateNested({ each: true })
    @Type(() => WorkspaceUsers)
    @Prop({ required: false, type: () => [WorkspaceUsers], default: [] })
    users: WorkspaceUsers[];
}

执行的聚合查询

const aggregationQuery: PipelineStage[] = [];

aggregationQuery.push({
    $unwind: '$users',
});

aggregationQuery.push({
    $lookup: {
        from: 'new_users',
        localField: 'users.userID',
        foreignField: '_id',
        as: 'userData',
    },
});

问题原因与解决办法

核心问题:类型不匹配

new_users集合的_id是ObjectId类型,但workspaces集合中users.userID被定义为String类型。MongoDB的$lookup是严格匹配,字符串格式的ID和ObjectId类型无法匹配,导致返回空数组。

解决步骤

1. 修正数据类型定义

把WorkspaceUsers中的userID类型改为Types.ObjectId,确保和UserEntity的_id类型一致:

export class WorkspaceUsers {
    // ...其他字段
    @Expose()
    @Prop({ required: true, type: Types.ObjectId, ref: () => UserEntity })
    userID: Types.ObjectId;
}

2. 处理已有数据(如果存在历史数据)

如果数据库中已经存储了字符串格式的userID,需要将其转换为ObjectId:

// 执行这个更新操作,将字符串userID转为ObjectId
db.workspaces.updateMany(
  {},
  [
    {
      $set: {
        "users.userID": {
          $map: {
            input: "$users",
            as: "user",
            in: { $toObjectId: "$$user.userID" }
          }
        }
      }
    }
  ]
)

3. 可选:如果暂时无法修改类型,在查询中转换

如果不能直接修改数据类型,可以在聚合查询中把users.userID转换为ObjectId后再执行$lookup:

const aggregationQuery: PipelineStage[] = [];

aggregationQuery.push({
    $unwind: '$users',
});

// 添加类型转换步骤
aggregationQuery.push({
    $addFields: {
        "users.userID": { $toObjectId: "$users.userID" }
    }
});

aggregationQuery.push({
    $lookup: {
        from: 'new_users',
        localField: 'users.userID',
        foreignField: '_id',
        as: 'userData',
    },
});

内容的提问来源于stack exchange,提问作者Raju Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:17:42