MongoDb:管道内部查找错误:错误:参数必须是聚合管道运算符

Posted

技术标签:

【中文标题】MongoDb:管道内部查找错误:错误:参数必须是聚合管道运算符【英文标题】:MongoDb: Pipeline inside lookup error: Error: Arguments must be aggregate pipeline operators 【发布时间】:2021-06-12 11:48:37 【问题描述】:

我有这三个模型:

    Institution模特:
const InstitutionSchema = new Schema(
  current_students: [
    
      type: Schema.Types.ObjectId,
      ref: "users",
    ,
  ],
);

module.exports = Institution = mongoose.model("institutions", InstitutionSchema);

current_students 字段中有对User 模型的引用数组。

    User模特:
const UserSchema = new Schema(
  profile: 
    type: Schema.Types.ObjectId,
    ref: "profiles",
  ,
);

module.exports = User = mongoose.model("users", UserSchema);

profile 字段中引用了Profile 模型。

    Profile模特:
const ProfileSchema = new Schema(
  videoURL: 
    type: String,
  ,
);

module.exports = Profile = mongoose.model("profiles", ProfileSchema);

我正在尝试获取Profile.videoURL 不是nullundefined 的机构用户的配置文件列表。这是我尝试过的:

Institution.aggregate([
  
    $lookup: 
      from: "users",
      localField: "current_students",
      foreignField: "_id",
      as: "current_student",
    ,
  ,
  
    $unwind: 
      path: "$current_student",
      preserveNullAndEmptyArrays: true,
    ,
  ,
  
    $lookup: 
      from: "profiles",
      localField: "current_student.profile",
      foreignField: "_id",
      as: "current_student_profile",
    ,
    pipeline: [
      
        $match: 
          videoURL:  $nin: [undefined, null] ,
        ,
      ,
    ],
  ,
]);

但是,由于执行$match 操作的最后一个管道,我不断收到此错误。

Error: Arguments must be aggregate pipeline operators

知道如何解决这个问题吗?

【问题讨论】:

【参考方案1】:

您的查询是错误的。你不能像那样通过pipeline。看看$lookup 语法。另外,如果您想了解有关聚合的更多信息,我建议您使用 MongoDB 自己提供的 Aggregation course。对所有人免费。

试试这个查询:

db.institutions.aggregate([
    
        $lookup: 
            from: "users",
            localField: "current_students",
            foreignField: "_id",
            as: "current_student",
        
    ,
    
        $unwind: 
            path: "$current_student",
            preserveNullAndEmptyArrays: true,
        
    ,
    
        $lookup: 
            from: "profiles",
            localField: "current_student.profile",
            foreignField: "_id",
            as: "current_student_profile",
        
    ,
     $unwind: "$current_student_profile" ,
    
        $match: 
            "current_student_profile.videoURL":  $nin: [undefined, null] ,
        
    
]);

输出:

/* 1 createdAt:3/13/2021, 6:18:26 PM*/

    "_id" : ObjectId("604cb49a6b2dcb17e8b152b2"),
    "name" : "Institute 1",
    "current_students" : [
        ObjectId("604cb4c36b2dcb17e8b152b8"),
        ObjectId("604cb4c36b2dcb17e8b152b9")
    ],
    "current_student" : 
        "_id" : ObjectId("604cb4c36b2dcb17e8b152b8"),
        "name" : "Dheemanth Bhat",
        "profile" : ObjectId("604cb4b16b2dcb17e8b152b5")
    ,
    "current_student_profile" : 
        "_id" : ObjectId("604cb4b16b2dcb17e8b152b5"),
        "videoURL" : "http://abc1@xyz.com"
    
,

/* 2 createdAt:3/13/2021, 6:18:26 PM*/

    "_id" : ObjectId("604cb49a6b2dcb17e8b152b3"),
    "name" : "Institute 2",
    "current_students" : [
        ObjectId("604cb4c36b2dcb17e8b152ba")
    ],
    "current_student" : 
        "_id" : ObjectId("604cb4c36b2dcb17e8b152ba"),
        "name" : "Alex Rider",
        "profile" : ObjectId("604cb4b16b2dcb17e8b152b7")
    ,
    "current_student_profile" : 
        "_id" : ObjectId("604cb4b16b2dcb17e8b152b7"),
        "videoURL" : "http://abc3@xyz.com"
    

测试数据:

users收藏:

/* 1 createdAt:3/13/2021, 6:19:07 PM*/

    "_id" : ObjectId("604cb4c36b2dcb17e8b152b8"),
    "name" : "Dheemanth Bhat",
    "profile" : ObjectId("604cb4b16b2dcb17e8b152b5")
,

/* 2 createdAt:3/13/2021, 6:19:07 PM*/

    "_id" : ObjectId("604cb4c36b2dcb17e8b152b9"),
    "name" : "Ahmed Ghrib",
    "profile" : ObjectId("604cb4b16b2dcb17e8b152b6")
,

/* 3 createdAt:3/13/2021, 6:19:07 PM*/

    "_id" : ObjectId("604cb4c36b2dcb17e8b152ba"),
    "name" : "Alex Rider",
    "profile" : ObjectId("604cb4b16b2dcb17e8b152b7")

profiles收藏:

/* 1 createdAt:3/13/2021, 6:18:49 PM*/

    "_id" : ObjectId("604cb4b16b2dcb17e8b152b5"),
    "videoURL" : "http://abc1@xyz.com"
,

/* 2 createdAt:3/13/2021, 6:18:49 PM*/

    "_id" : ObjectId("604cb4b16b2dcb17e8b152b6")
,

/* 3 createdAt:3/13/2021, 6:18:49 PM*/

    "_id" : ObjectId("604cb4b16b2dcb17e8b152b7"),
    "videoURL" : "http://abc3@xyz.com"

institutions收藏

/* 1 createdAt:3/13/2021, 6:18:26 PM*/

    "_id" : ObjectId("604cb49a6b2dcb17e8b152b2"),
    "name" : "Institute 1",
    "current_students" : [
        ObjectId("604cb4c36b2dcb17e8b152b8"),
        ObjectId("604cb4c36b2dcb17e8b152b9")
    ]
,

/* 2 createdAt:3/13/2021, 6:18:26 PM*/

    "_id" : ObjectId("604cb49a6b2dcb17e8b152b3"),
    "name" : "Institute 2",
    "current_students" : [
        ObjectId("604cb4c36b2dcb17e8b152ba")
    ]

【讨论】:

【参考方案2】:

必须是这样的:

Institution.aggregate([
  
    $lookup: 
      from: "users",
      localField: "current_students",
      foreignField: "_id",
      as: "current_student",
    ,
  ,
  
    $unwind: 
      path: "$current_student",
      preserveNullAndEmptyArrays: true,
    ,
  ,
  
    $lookup: 
      from: "profiles",
      localField: "current_student.profile",
      foreignField: "_id",
      as: "current_student_profile",
    
   ,
   
     $match: 
       videoURL:  $nin: [undefined, null] ,
     ,
   
]);

注意,这看起来像是关系 RDBMS 设计的“一对一”转换。通常它不是将每个表格转换为集合的最佳方法,通常集合应该有不同的设计。

【讨论】:

这将返回一个空数组。我认为这是有道理的,因为 videoURL 是 Profile 模型中的字段,而不是机构模型中的字段。因此,正如您编写的那样,它检查的是 Institution.videoURL 而不是 Profile.videoURL,因此它始终是未定义的,并且返回的结果是一个空数组。

以上是关于MongoDb:管道内部查找错误:错误:参数必须是聚合管道运算符的主要内容,如果未能解决你的问题,请参考以下文章

错误信息查找管道必须是字符串,是数组类型

MongoDB 聚合错误:管道阶段规范对象必须只包含一个字段

Mongoose Arguments 必须是聚合管道操作符

Scikit-learn 管道类型错误:zip 参数 #2 必须支持迭代

java spring 中使用 AggregationOperation 的 Mongodb 内部连接:错误 [需要'cursor' 选项,但带有解释参数的聚合除外]

错误:活动上的查找必须具有唯一的域