使用$ group和$ lookup嵌套属性在MongoDB上加入2个文档

时间:2019-01-06 15:59:50

标签: mongodb mongoose mongodb-query aggregation-framework

我有2个要基于特定属性加入的不同文档。 在第一个文档上,我想使用$ group根据属性对文档进行分组,然后使用结果将其与第二个文档联接。

我的第一个文档spotmodel具有以下结构:

{
"_id" : ObjectId("5c17724498ea721018ba9d59"),
"code" : "AD01",
"streetId" : ObjectId("5c16d3e6e6cbea23a0393b4b")
},
{
"_id" : ObjectId("5c17724498ea721018ba9d60"),
"code" : "AD02",
"streetId" : ObjectId("5c16d3e6e6cbea23a0393b4b")
}
// other documents with same or different streetID

我的第二个文档areamodel具有以下结构:

{
"_id" : ObjectId("5c16d339e6cbea23a0393b47"),
"description" : "Area A",
"streets" : [
    {
    "_id" : ObjectId("5c16d3e6e6cbea23a0393b4b"),
    "name" : "Waterloo"
    },
    {
    "_id" : ObjectId("5c16d536e6cbea23a0393b51"),
    "name" : "Bristol"
    }   
    ]
}
,
{
"_id" : ObjectId("5c16d339e6cbea23a0393b47"),
"description" : "Area B",
"streets" : [
    {
    "_id" : ObjectId("5c16d3e6e6cbea23a0393b2a"),
    "name" : "Park Av."
    },
    {
    "_id" : ObjectId("5c16d536e6cbea23a0393b2b"),
    "name" : "Nelson St."
    }   
    ]
}

我想基于spotmodelstreetId文档进行分组,并在areamodel匹配streetId时使用此分组查询与streets._id文档进行合并

到目前为止,我有以下查询:

db.spotmodel.aggregate([
{
$group: {
  _id: "$streetId",
  codes: {
    $push: {
      code: "$code",
    }
  }
}
},
{$lookup: {
     from: "db.areamodel",
     localField: "streets._id",
     foreignField: "_id",
     as: "details"
   }},
 {$match:{details:{$ne:[]}}}
 ])

但是此代码为我提供了一个空数组[],但我期望的结果是这样的:

{
"_id" : ObjectId("5c16d339e6cbea23a0393b47"),
"description" : "Area A",
"streets" : [
    {
    "_id" : ObjectId("5c16d3e6e6cbea23a0393b4b"),
    "name" : "Waterloo",
    "codes":[
        {
        "code": "AD01"
        },
        {
        "code": "AD02"
        }
    ]
    },
    {
    "_id" : ObjectId("5c16d536e6cbea23a0393b51"),
    "name" : "Bristol"
    }   
    ]
}

我的错误在哪里?

3 个答案:

答案 0 :(得分:1)

您可以在aggregation下使用

db.areamodel.aggregate([
  { "$unwind": "$streets" },
  { "$lookup": {
    "from": "spotmodel",
    "localField": "streets._id",
    "foreignField": "streetId",
    "as": "codes"
  }},
  { "$addFields": { "streets.codes": "$codes.code" }},
  { "$group": {
    "_id": "$_id",
    "streets": { "$push": "$streets" },
    "description": { "$first": "$description" }
  }}
])

答案 1 :(得分:0)

在mongodb中,大型数据集的查找速度非常慢。 尝试对文档进行非规范化。

答案 2 :(得分:0)

// schema on nodejs via mongoose:
var mongoose = require('mongoose')
    , Schema = mongoose.Schema
    , ObjectId = Schema.ObjectId;

var flatSchema = new Schema({
    _id: ObjectId,
    rentType: Number,
    price: Number,
    thumbnail: String,
    address: {
        country: String,
        city: String,
        street: String,
        district: Number
        // ... more fields
    }
    // ... some more fields
}, { collection: 'flats'});

module.exports = mongoose.model('Flat', flatSchema);
-----
/ e.g. let's define request
    var rules = [{'address.city': '1'}, {price: {$gte: 200}}];

    // and here are the grouping request:
    Flat.aggregate([
        { $match: {$and: rules } },
        {
            $project: {
                _id: 0, // let's remove bson id's from request's result
                price: 1, // we need this field
                district: '$address.district' // and let's turn the nested field into usual field (usual renaming)
            }
        },
        {
            $group: {
                _id: '$district', // grouping key - group by field district
                minPrice: { $min: '$price'}, // we need some stats for each group (for each district)
                maxPrice: { $max: '$price'},
                flatsCount: { $sum: 1 }
            }
        }
    ], {}, callback);
First of all – it’s not possible to group by nested field, e.g. “address.district”, thats why we workarounded this by field’s renaming in $project.