基于名称的MongoDB / Mongoose加入

时间:2018-07-26 12:06:14

标签: node.js mongodb mongoose

我目前有一个产品架构,该架构具有一个包含数量不同的对象的属性数组。一个对象看起来像这样:

  

[{属性:'颜色',值:'黑色'},{属性:'长度',值:'1英寸'}]

每种产品都有随机数量的属性。问题是我无法查找产品并通过其标识符获取其属性。

下面是产品架构。

const mongoose = require('mongoose');

let product = new mongoose.Schema({
    id: { type: mongoose.Schema.Types.ObjectId },
    created_at: { type: Date, default: new Date()},
    language: { type: String, required: true },
    category: { type: String },
    articlenumber: { type: String },
    name: { type: String },
    properties: { type: [{}] }
});

module.exports = product;

我的属性集合中也有一个带有标识符的属性架构。

const mongoose = require('mongoose');

let property = new mongoose.Schema({
    id: { type: mongoose.Schema.Types.ObjectId },
    categoryPropertyId: { type: String },
    language: { type: String },
    name: { type: String, unique: true }
});

module.exports = property;
  

{id:ObjectID,categoryPropertyId:“ 317”,语言:“ US”,名称:“ Color”}

我想获得一个产品,并根据其名称和语言加入,并获得categoryPropertyId。

猫鼬有可能吗?我可以使用javascript循环来做到这一点,但希望加入类似的内容。

我已经看过$ lookup并进行填充,但是我对猫鼬不是那么熟练。任何帮助表示赞赏!

产品

{
    _id: 5b3f18d93098293c4ab0ca4a,
    created_at: ‘2018-07-06 09:22:45.377’,
    language: ‘US’,
    category: ‘Phones’,
    articlenumber: ‘6700’,
    name: ‘Sony Phone’
    properties: [
    {
        property: ‘Version’,
        helptext: ‘’,
        value: ’8.0’    
    },
    {
        property: ‘Operating System’,
        helptext: ‘’,
        value: ‘Android’
    }]
}

属性数据集

[
    {
        id: ‘5b3603a56a14e1072ba6f4ef’,
        categoryPropertyId: ’429’,
        language: ‘US’,
        name: ‘Android’
    },
    {
        id: ‘5b3603a56a14e1072ba6f4ef’,
        categoryPropertyId: ’977’,
        language: ‘US’,
        name: ‘Version’
    },
    {
        id: ‘5b3603a56a14e1072ba6f4ef’,
        categoryPropertyId: ’1033’,
        language: ‘US’,
        name: ‘Weight’
    }
]

预期产量

{
    _id: 5b3f18d93098293c4ab0ca4a,
    created_at: ‘2018-07-06 09:22:45.377’,
    language: ‘US’,
    category: ‘Phones’,
    articlenumber: ‘6700’,
    name: ‘Sony Phone’
    properties: [
        {
            property: ‘Version’,
            helptext: ‘’,
            value: ’8.0’,
            categoryPropertyId: ’977’
        },
        {
            property: ‘Operating System’,
            helptext: ‘’,
            value: ‘Android’,
            categoryPropertyId: ’429’
        }
    ]
}

2 个答案:

答案 0 :(得分:1)

尝试以下代码:

db.getCollection("products").aggregate(

    // Pipeline
    [
        // Stage 1
        {
            $unwind: {
                path : "$properties",
                includeArrayIndex : "arrayIndex", // optional
                preserveNullAndEmptyArrays : false // optional
            }
        },

        // Stage 2
        {
            $lookup: // Equality Match
            {
                from: "properties",
                localField: "properties.value",
                foreignField: "name",
                as: "newData"
            }
        },

        // Stage 3
        {
            $unwind: {
                path : "$newData",
                includeArrayIndex : "arrayIndex", // optional
                preserveNullAndEmptyArrays : false // optional
            }
        },

        // Stage 4
        {
            $project: {
                "language": "$language",
                "category" : "$category", 
                "articlenumber" : "$articlenumber", 
                "name" : "$name", 
                "properties": {
                  "property":"$properties.property",
                  "helptext": "$properties.helptext",
                  "value":"$properties.value",
                  "categoryPropertyId":"$newData.categoryPropertyId"
                }
            }
        },

        // Stage 5
        {
            $group: {
                    "_id": "$_id",
                    "properties": { "$push": "$properties" },
                    "language": { "$first": "$language" },
                    "category": { "$first": "$category" },
                    "articlenumber": { "$first": "$articlenumber" },
                    "name": { "$first": "$name" }
                }
        },

    ]

);

希望这可以解决您的查询。

答案 1 :(得分:1)

您可以尝试以下汇总

基本上,您需要先$unwind "properties"数组才能与外来的“名称”相匹配... let允许您 保留从根文档(产品)到内部文档(属性)的字段,最后使用$group 您可以将拆分的“属性”再次回滚到“属性”数组。

如果您有mongodb 3.6版

db.product.aggregate([
  { "$unwind": "$properties" },
  { "$lookup": {
    "from": Properties.collection.name,
    "let": { "property": "$properties.property" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": [ "$name", "$$property" ] } } },
      { "$project": { "categoryPropertyId": 1 }}
    ],
    "as": "properties.prop"
  }},
  { "$unwind": "$properties.prop" },
  { "$addFields": { 
    "properties.categoryPropertyId": "$properties.prop.categoryPropertyId" 
  }},
  { "$project": { "properties.prop": 0 }},
  { "$group": {
    "_id": "$_id",
    "created_at": { "$first": "$created_at" },
    "language": { "$first": "$language" },
    "category": { "$first": "$category" },
    "articlenumber": { "$first": "$articlenumber" },
    "name": { "$first": "$name" },
    "properties": { "$push": "$properties" }
  }}
])

,如果您的mongodb版本低于3.6

db.product.aggregate([
  { "$unwind": "$properties" },
  { "$lookup": {
    "from": Properties.collection.name,
    "localField": "properties.property",
    "foreignField": "name",
    "as": "properties.prop"
  }},
  { "$unwind": "$properties.prop" },
  { "$addFields": { 
    "properties.categoryPropertyId": "$properties.prop.categoryPropertyId" 
  }},
  { "$project": { "properties.prop": 0 }},
  { "$group": {
    "_id": "$_id",
    "created_at": { "$first": "$created_at" },
    "language": { "$first": "$language" },
    "category": { "$first": "$category" },
    "articlenumber": { "$first": "$articlenumber" },
    "name": { "$first": "$name" },
    "properties": { "$push": "$properties" }
  }}
])