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

时间:2021-03-15 07:50:25

标签: mongodb mongoose aggregation-framework lookup mongoose-populate

我有这三个模型:

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

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

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

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

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

Profile 字段中引用了 profile 模型。

  1. 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

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

2 个答案:

答案 0 :(得分: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")
    ]
}

答案 1 :(得分:0)

一定是这样的:

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 设计的“一对一”转换。通常将每个表格转换为集合并不是最好的方法,通常集合应该有不同的设计。