【问题标题】:Return custom results using the Aggregate framework使用聚合框架返回自定义结果
【发布时间】:2019-12-02 23:01:47
【问题描述】:

我的 Node.js 应用中有以下架构:

let CategorySchema = mongoose.Schema({        
    name: { type: String, required: true }
});

let UserSchema = mongoose.Schema({
        firstName: { type: String, required: true },
        lastName: { type: String, required: true }
});

let CustomerSchema = mongoose.Schema({        
    name: { type: String, required: true }
});

let VendorSchema = mongoose.Schema({
    userID: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
    category: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }],
    products: [ { type: mongoose.Schema.Types.ObjectId, ref: 'Product' } ],
    name: { type: String, required: true }
});

let ProductSchema = mongoose.Schema({        
        vendorID: { type: mongoose.Schema.Types.ObjectId, ref: 'Vendor' },
        name: { type: String, index: true, required: true },      
        customerReviews: [{
            stars: { type: Number, required: false },
            review: { type: String, required: false },
            customerId: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true }
        }]
});

我正在尝试查询 Vendors 集合以返回以下结果:

{
    _id: "dsi9dsik129dkdsdsds",
    userData: {
    _id: "dsa9dskd2kwd29dkkss",
    firstName: "Michael",
    lastName: "White"
    },
    categoryData: {
    _id: "e9dids91i239dskds91",
    name: "Category A"
    },
    productsData: [ {
    _id: "3132139i31j32131",
    vendorID: "dsi9dsik129dkdsdsds",
    name: "Product ABC",
    customerReviews [{
        stars: "5",
            review: "Good",
        customerData: {
        _id: "zds91i232131j2321j",
        name: "John silver"
        }
    },
    {
        stars: "3",
            review: "Bad",
        customerData: {
        _id: "ldso91232131j2321j",
        name: "Mark Spenser"
        }
    }]
    } ],
    name: "Vendor XYZ"
}

我已经在 Vendors 集合(意思是 Vendors.aggregate(...) )上构建了以下查询,但我不确定如何格式化返回的结果以及检索客户中的客户数据评论,所以我想知道是否有人可以提供帮助?谢谢。

(
 { $lookup: { from: "users", localField: "userID", foreignField: "_id", as: "userData"  } },
 { $lookup: { from: "categories", localField: "category", foreignField: "_id", as: "categoryData"  } },
 { $lookup: { from: "products", localField: "products", foreignField: "_id", as: "productsData"  } },
 { $group: { _id: null, content: { $push: '$$ROOT' },count: { $sum: 1 } } },
 { $project: { content: { $slice: [ '$content', 0, 10 ] }, count: 1, _id: 0 } },
)

测试:

Category:
{
    "_id" : ObjectId("5de7fc530ce9d05be4024170"),
    "categoryName" : "Glass",
    "__v" : 0
}

User:
{
    "_id" : ObjectId("5d6671ae7be3be4e18ebe9bb"),
    "firstName" : "Mark",
    "lastName" : "Smith",
    "__v" : 0
}

Customer:
{
    "_id" : ObjectId("5dd7cb11f4b2544253368f24"),
    "customerName" : "Michael White",
    "__v" : 0
}

Vendor:
{
    "_id" : ObjectId("5de7fc6a0ce9d05be4024171"),
    "category" : [ 
        ObjectId("5de7fc530ce9d05be4024170")
    ],
    "products" : [ 
        ObjectId("5de8474ccd0bbc05256db819")
    ],
    "userID" : ObjectId("5d6671ae7be3be4e18ebe9bb"),
    "vendorName" : "Michael White",
    "__v" : 0
}

Product:
{
    "_id" : ObjectId("5de8474ccd0bbc05256db819"),
    "vendorID" : ObjectId("5de7fc6a0ce9d05be4024171"),
    "name" : "Red Sause",
    "customerReviews" : [ 
        {
            "moderated" : false,
            "_id" : ObjectId("5de7fcf20ce9d05be4024175"),
            "customerId" : ObjectId("5dd7cb11f4b2544253368f24"),
            "stars" : 3,
            "review" : "Didn't like it that much :( ",
            "date" : ISODate("2019-12-04T18:37:38.253Z")
        }
    ],
    "__v" : 0
}

注意:我在上面的测试中在名称之前添加了实体名称,例如。 vendorName / customerName 只是为了避免跨多个集合的字段“名称”之间的混淆

【问题讨论】:

  • 你能添加一些测试吗?

标签: mongodb aggregation-framework


【解决方案1】:

您可以从 3.6 版本开始尝试以下聚合。

{"$lookup":{ 
    "from": "users", 
    "localField": "userID", 
    "foreignField": "_id",
    "as": "userData"  
}},
{"$unwind":"$userData"},
{"$lookup":{ 
    "from": "categories", 
    "localField": "category", 
    "foreignField": "_id",
    "as": "categoryData"  
}},
{"$lookup":{ 
   "from":"products",
   "let":{"products":"$products"},
   "pipeline":[
     {"$match":{"$expr":{"$in":["$_id","$$products"]}}},
     {"$unwind":{"path":"$customerReviews", "preserveNullAndEmptyArrays":true}},         
     {"$lookup":{
      "from":"customers",
      "localField":"customerReviews.customerId",
      "foreignField":"_id",
      "as":"customerData"
     }},
    {"$unwind":{"path":"$customerData", "preserveNullAndEmptyArrays":true}}, 
    {"$group":{
      "_id":"$_id",
      "vendorID": {"$first":"$vendorID"},
      "name": {"$first":"$name"},
      "customerReviews":{
         "$push":{ 
           "stars": "$customerReviews.stars",
           "review": "$customerReviews.review",
           "customerData":"$customerData"
          }
        }
     }}
  ],
  "as":"productsData"
}}

【讨论】:

  • 感谢您的努力,categoryData 和 userData 完美返回,但产品总是返回空,所以我想知道我是否在这里遗漏了什么?谢谢
  • Np。没有测试数据我什么也说不出来。您可以更新帖子以包含您的测试数据吗?
  • 我已经编辑了问题,添加了一些测试数据。我还在“名称”字段中添加了前缀实体名称,以避免在不同集合中的名称字段之间产生混淆。再次感谢您的时间和努力。
  • Np。刚刚验证。我可以看到您发布的示例数据的产品数据。可能是您没有对某些产品的客户评论。您可以尝试$unwind"preserveNullAndEmptyArrays":true 选项以在它们为空或丢失时保留该行。更新了答案..另外请验证查询中的集合名称是否正确。
猜你喜欢
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
  • 2018-08-01
  • 2021-03-30
  • 2020-09-05
  • 2021-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多