Javascript Mongodb获取所有集合项上的arrayitems计数

Javascript Mongodb获取所有集合项上的arrayitems计数,javascript,mongodb,Javascript,Mongodb,我有这样一个mongodb系列: { _id: 123, name: 'some name', category: 17, sizes: ['XS', 'S', 'XL'] }, { _id: 124, name: 'another name', category: 17, sizes: ['S', 'L', '2XL'] } 我需要两种不同的方法。第一个问题:在一个特定的类别中,每种尺寸有多少个项目可用 { 17: {

我有这样一个mongodb系列:

{
    _id: 123,
    name: 'some name',
    category: 17,
    sizes: ['XS', 'S', 'XL']
},
{
    _id: 124,
    name: 'another name',
    category: 17,
    sizes: ['S', 'L', '2XL']
}
我需要两种不同的方法。第一个问题:在一个特定的类别中,每种尺寸有多少个项目可用

{
    17: {
        XS: 0,
        S:  19,
        M:  100
    },
    39: {
        XS: 5,
        ...
    }
}
也可以采用一种解决方案,仅显示该尺寸的物品是否可用:

{
    17: {
        XS: false,
        S:  true,
        M:  true,
        ...
    },
    39: {
        XS: true,
        ...
    }
}
第二个问题:我需要相同的,但在对名称执行全文搜索之后

我已经尝试过在这些字段上进行转换,但对于如何在阵列上执行转换,我有点不知所措

谢谢你的帮助


更新

在来自的帮助下,我更进一步:

db.so.aggregate(
    [
        // First, filter by name or something else
        // this could also include the category
        { 
            $match: {
                'name': {
                    $regex: /other.*/i
                }
            }
        },

        // explode the sizes-array into single documents
        { '$unwind': '$sizes' },

        // group and count
        { '$group': {
            '_id': '$sizes',
            'count': { '$sum': 1 }
        }}
    ]
)

仍然缺少:按类别执行此操作

以下是我插入的一些示例数据:

/* 1 */
{
    "_id" : 123,
    "name" : "some name",
    "category" : 17,
    "sizes" : [ 
        "XS", 
        "S", 
        "XL"
    ]
}

/* 2 */
{
    "_id" : 124,
    "name" : "another name",
    "category" : 17,
    "sizes" : [ 
        "S", 
        "L", 
        "2XL"
    ]
}

/* 3 */
{
    "_id" : 125,
    "name" : "name",
    "category" : 35,
    "sizes" : [ 
        "S", 
        "L", 
        "2XL"
    ]
}
用例1 在您的第一个用例中,您似乎希望按照大小和类别进行分组。实际上,您可以按多个键进行分组,下面是一个示例:

db.so.aggregate([
    // add your match here...
    {
        '$unwind': '$sizes' // flatten your array
    },
    // group and count
    {
        '$group': {
            '_id': {
                sizes: '$sizes',
                category: '$category'
            }, // group by both sizes and category
            'count': {
                '$sum': 1
            },

        }
    },
    {
        '$group': {
            '_id': '$category', // group by category now
            sizeCount: { // create an array that includes the size and the count for that size
                $push: { 
                    size: "$sizes",
                    count: "$count"
                }
            }

        }
    }
])
此管道将创建以下结果:

{
    "_id" : 17,
    "sizeCount" : [ 
        {
            "size" : "2XL",
            "count" : 1.0
        }, 
        {
            "size" : "XS",
            "count" : 1.0
        }, 
        {
            "size" : "S",
            "count" : 2.0
        }, 
        {
            "size" : "XL",
            "count" : 1.0
        }, 
        {
            "size" : "L",
            "count" : 1.0
        }
    ]
}
你能接受吗

用例2 现在,关于您的第二个用例,您希望如何对该类别中甚至不存在的大小进行分组? 但一般来说,您可以通过使用

因此,在同一示例中,如果应用此管道:

db.so.aggregate([
    // add your match here ...
    {
        '$unwind': '$sizes' // flatten your array
    },
    // group and count
    {
        '$group': {
            '_id': {
                sizes: '$sizes',
                category: '$category'
            }, // group by both sizes and category
            'count': {
                '$sum': 1
            },

        }
    },
    {
        '$project': {
            _id: 0,
            'count': {
                $cond: [{
                    $eq: ["$count", 1.0]
                }, "Limited", "Many"]
            },
            category: "$_id.category",
            sizes: "$_id.sizes"
        }
    },
    {
        '$group': {
            '_id': '$category',
            sizeCount: {
                $push: {
                    size: "$sizes",
                    count: "$count"
                }
            }

        }
    }
])
它将产生以下结果(一个示例):

所以基本上在这行中,
$cond:[{$eq:[“$count”,1.0]},“Limited”,“Many”]}

我们说,如果
count
字段仅为1.0,那么该尺寸的衬衫是有限的,否则我们有很多。您可以应用任何比较运算符,因此还可以执行以下操作:
$cond:[{$lte:[“$count”,2.0]},“Limited”,“Many”]}

以下是我插入的一些示例数据:

/* 1 */
{
    "_id" : 123,
    "name" : "some name",
    "category" : 17,
    "sizes" : [ 
        "XS", 
        "S", 
        "XL"
    ]
}

/* 2 */
{
    "_id" : 124,
    "name" : "another name",
    "category" : 17,
    "sizes" : [ 
        "S", 
        "L", 
        "2XL"
    ]
}

/* 3 */
{
    "_id" : 125,
    "name" : "name",
    "category" : 35,
    "sizes" : [ 
        "S", 
        "L", 
        "2XL"
    ]
}
用例1 在您的第一个用例中,您似乎希望按照大小和类别进行分组。实际上,您可以按多个键进行分组,下面是一个示例:

db.so.aggregate([
    // add your match here...
    {
        '$unwind': '$sizes' // flatten your array
    },
    // group and count
    {
        '$group': {
            '_id': {
                sizes: '$sizes',
                category: '$category'
            }, // group by both sizes and category
            'count': {
                '$sum': 1
            },

        }
    },
    {
        '$group': {
            '_id': '$category', // group by category now
            sizeCount: { // create an array that includes the size and the count for that size
                $push: { 
                    size: "$sizes",
                    count: "$count"
                }
            }

        }
    }
])
此管道将创建以下结果:

{
    "_id" : 17,
    "sizeCount" : [ 
        {
            "size" : "2XL",
            "count" : 1.0
        }, 
        {
            "size" : "XS",
            "count" : 1.0
        }, 
        {
            "size" : "S",
            "count" : 2.0
        }, 
        {
            "size" : "XL",
            "count" : 1.0
        }, 
        {
            "size" : "L",
            "count" : 1.0
        }
    ]
}
你能接受吗

用例2 现在,关于您的第二个用例,您希望如何对该类别中甚至不存在的大小进行分组? 但一般来说,您可以通过使用

因此,在同一示例中,如果应用此管道:

db.so.aggregate([
    // add your match here ...
    {
        '$unwind': '$sizes' // flatten your array
    },
    // group and count
    {
        '$group': {
            '_id': {
                sizes: '$sizes',
                category: '$category'
            }, // group by both sizes and category
            'count': {
                '$sum': 1
            },

        }
    },
    {
        '$project': {
            _id: 0,
            'count': {
                $cond: [{
                    $eq: ["$count", 1.0]
                }, "Limited", "Many"]
            },
            category: "$_id.category",
            sizes: "$_id.sizes"
        }
    },
    {
        '$group': {
            '_id': '$category',
            sizeCount: {
                $push: {
                    size: "$sizes",
                    count: "$count"
                }
            }

        }
    }
])
它将产生以下结果(一个示例):

所以基本上在这行中,
$cond:[{$eq:[“$count”,1.0]},“Limited”,“Many”]}

我们说,如果
count
字段仅为1.0,那么该尺寸的衬衫是有限的,否则我们有很多。您可以应用任何比较运算符,因此还可以执行以下操作:
$cond:[{$lte:[“$count”,2.0]},“Limited”,“Many”]}
注意:投影将很快添加

你可以

展开
->
按类别和大小分组
->
按类别分组并推送
->
项目

请参考以下查询。这将给出一个没有任何投影的结果。我会很快添加投影以符合您的要求

var group_by_category_and_sizes = { 
  "$group": { 
    "_id": { 
        "category": "$category", 
        "size": "$sizes"
      }, 
      "count": { 
        "$sum": 1 
      } 
    } 
  }

var group_by_category_and_push = {
  "$group": {
    "_id": {
      "category": "$_id.category"
    }, 
    "combine": {
      "$push": { "size": "$_id.size", "count": "$count" }
    }
  }
}

db.clothings.aggregate([{ "$unwind": "$sizes" }, group_by_category_and_sizes, group_by_category_and_push])
文件

{name:'some name',类别:17,大小:['XS','S','XL']}

{name:'other name',类别:17,大小:['S','L','2XL']}

{name:'other name',类别:18,大小:['M','S','L']}

这将产生

{
    "_id": {
        "category": 18
    },
    "combine": [{
        "size": "L",
        "count": 1
    }, {
        "size": "S",
        "count": 1
    }, {
        "size": "M",
        "count": 1
    }]
} {
    "_id": {
        "category": 17
    },
    "combine": [{
        "size": "2XL",
        "count": 1
    }, {
        "size": "S",
        "count": 2
    }, {
        "size": "XL",
        "count": 1
    }, {
        "size": "L",
        "count": 1
    }, {
        "size": "XS",
        "count": 1
    }]
}

注意:投影将很快添加

你可以

展开
->
按类别和大小分组
->
按类别分组并推送
->
项目

请参考以下查询。这将给出一个没有任何投影的结果。我会很快添加投影以符合您的要求

var group_by_category_and_sizes = { 
  "$group": { 
    "_id": { 
        "category": "$category", 
        "size": "$sizes"
      }, 
      "count": { 
        "$sum": 1 
      } 
    } 
  }

var group_by_category_and_push = {
  "$group": {
    "_id": {
      "category": "$_id.category"
    }, 
    "combine": {
      "$push": { "size": "$_id.size", "count": "$count" }
    }
  }
}

db.clothings.aggregate([{ "$unwind": "$sizes" }, group_by_category_and_sizes, group_by_category_and_push])
文件

{name:'some name',类别:17,大小:['XS','S','XL']}

{name:'other name',类别:17,大小:['S','L','2XL']}

{name:'other name',类别:18,大小:['M','S','L']}

这将产生

{
    "_id": {
        "category": 18
    },
    "combine": [{
        "size": "L",
        "count": 1
    }, {
        "size": "S",
        "count": 1
    }, {
        "size": "M",
        "count": 1
    }]
} {
    "_id": {
        "category": 17
    },
    "combine": [{
        "size": "2XL",
        "count": 1
    }, {
        "size": "S",
        "count": 2
    }, {
        "size": "XL",
        "count": 1
    }, {
        "size": "L",
        "count": 1
    }, {
        "size": "XS",
        "count": 1
    }]
}

以下是您如何获得建议的确切输出文档:

db.so.aggregate({
    $unwind: "$sizes" // flatten the sizes array
}, {
    $group: {
        _id: { // group by both category and sizes
            category: "$category",
            size: "$sizes"
        },
        count: {
           $sum: 1 // count number of documents per bucket
        }
    }
}, {
    $group: {
        _id: "$_id.category", // second grouping to get entries per category
        sizes: {
           $push: { k: "$_id.size", v: "$count" } // create an array of key/value pairs which we will need in this exact shape in the next stage
        }
    }
}, {
    $project: {
        "magic": {
            $arrayToObject: // transform the key/value pair we generate below into a document
            [[{
                // the $substr is a hack to transform the numerical category (e.g. 17) 
                // into a string (not nice, probably not supported but working for now...)
                // which is needed for the above $arrayToObject to work
                k: { $substr: [ "$_id", 0, -1 ] }, 
                v: {
                    $arrayToObject: "$sizes" // turn the key/value pairs we created in the previous pipeline stage into a document
                }
            }]]
        }
    }
}, {
    $replaceRoot: {
        newRoot: "$magic" // promote our "magic" field to the document root
    }
})
请注意,虽然这为您提供了正确的输出,但我不一定建议您走这条路线,因为聚合管道相当庞大,内置了相当多的魔法,几乎没有什么可测量的好处。因此,如果您可以接受@Alex P建议的输出结构,那么这肯定会更容易理解和维护,也会更快


关于第二个场景:您可以在
$unwind
阶段之前添加任意数量的初步$match阶段,以过滤掉任何多余的数据。

以下是您可以获得建议的确切输出文档的方法:

db.so.aggregate({
    $unwind: "$sizes" // flatten the sizes array
}, {
    $group: {
        _id: { // group by both category and sizes
            category: "$category",
            size: "$sizes"
        },
        count: {
           $sum: 1 // count number of documents per bucket
        }
    }
}, {
    $group: {
        _id: "$_id.category", // second grouping to get entries per category
        sizes: {
           $push: { k: "$_id.size", v: "$count" } // create an array of key/value pairs which we will need in this exact shape in the next stage
        }
    }
}, {
    $project: {
        "magic": {
            $arrayToObject: // transform the key/value pair we generate below into a document
            [[{
                // the $substr is a hack to transform the numerical category (e.g. 17) 
                // into a string (not nice, probably not supported but working for now...)
                // which is needed for the above $arrayToObject to work
                k: { $substr: [ "$_id", 0, -1 ] }, 
                v: {
                    $arrayToObject: "$sizes" // turn the key/value pairs we created in the previous pipeline stage into a document
                }
            }]]
        }
    }
}, {
    $replaceRoot: {
        newRoot: "$magic" // promote our "magic" field to the document root
    }
})
请注意,虽然这为您提供了正确的输出,但我不一定建议您走这条路线,因为聚合管道相当庞大,内置了相当多的魔法,几乎没有什么可测量的好处。因此,如果您可以接受@Alex P建议的输出结构,那么这肯定会更容易理解和维护,也会更快


关于第二个场景:您可以在
$unwind
阶段之前添加任意数量的初步$match阶段,以过滤掉任何多余的数据。

您可以这样做:[{'$unwind':'$sizes'},{'$group':{'\u id':{'size':'$sizes',category':'$category'},'count':{'$sum':1}}}]要生成如下文档:{“\u id”:{“size”:“XS”,“category”:17},“count”:1.0}您可以这样做:[{'$unwind':'$sizes'},{'$group':{''u id':{'size':'$sizes','category':'$category'},'count':{'$sum':1}}}]生成如下文档:{“_id”:{“size”:“XS”,“category”:17},“count”:1.0}