Nodejs mongodb 增删改 多维数组的问题

Nodejs mongodb 增删改 多维数组的问题

<pre> var catList = [ { cat_name : ‘sport’, cat_desc : ‘第一个顶级分类.’, sub_cat: [ { cat_name : ‘sport_bag’, cat_desc : ‘sport的二级子分类.’, },{ cat_name : ‘sport_apparel’, cat_desc : ‘sport的二级子分类.’, sub_cat: [ { cat_name : ‘sport_apparel_men’, cat_desc : ‘sport的三级子分类.’ },{ cat_name : ‘sport_apparel_women’, cat_desc : ‘sport的三级子分类.’ } ] } ] },{ cat_name : ‘stationery’, cat_desc : ‘第二个顶级分类.’, sub_cat: [ { cat_name : ‘stationery_bag’, cat_desc : ‘stationery的二级子分类.’, },{ cat_name : ‘stationery_apparel’, cat_desc : ‘stationery的二级子分类.’, sub_cat: [ { cat_name : ‘stationery_apparel_men’, cat_desc : ‘sport的三级子分类.’ } ] } ] } ] </pre> 如上,这是mongodb 一个集合文档,存储的商品三级分类. 为了发挥mongodb的优势和查询方便,采用这种嵌入式。但是有些蛋疼的问题。 1:对里层数组做增删改的时候无法精确定位。如果再增加四级,五级。那更蛋疼。 2:如果结合商品表查询也不是很爽,每个商品有一个字段是商品分类名。比如:查询sport分类下的所有商品,那就要将sport分类下的数组一层一层循环得到所有分类。这样好像不是很爽。 那最后一个疑问:像这种商品分类和商品表,用mongodb数据库应该怎么样设计才是最后理的????有类似的例子看吗?求指教!


3 回复

针对你提到的问题,我们可以从几个方面来优化你的数据结构和查询方式。

1. 数据结构优化

首先,让我们考虑如何更好地组织你的数据结构。对于嵌套多层的分类信息,可以考虑使用扁平化的结构,或者引入引用的方式来处理。这样不仅可以简化增删改操作,还可以提高查询效率。

扁平化结构

将分类信息扁平化存储,每个分类都有一个唯一的ID,并且其父分类ID也明确指定。这使得任何层级的分类都能快速定位。

const categories = [
    { _id: 'sport', parent_id: null, name: 'Sport', description: '第一个顶级分类.' },
    { _id: 'sport_bag', parent_id: 'sport', name: 'Sport Bag', description: 'sport的二级子分类.' },
    { _id: 'sport_apparel', parent_id: 'sport', name: 'Sport Apparel', description: 'sport的二级子分类.' },
    { _id: 'sport_apparel_men', parent_id: 'sport_apparel', name: 'Sport Apparel Men', description: 'sport的三级子分类.' },
    { _id: 'sport_apparel_women', parent_id: 'sport_apparel', name: 'Sport Apparel Women', description: 'sport的三级子分类.' },
    // 更多分类...
];

引用结构

如果需要保持分类信息的嵌套关系,可以为每个分类维护一个指向父分类的引用。

const categories = [
    {
        _id: 'sport',
        name: 'Sport',
        description: '第一个顶级分类.',
        sub_categories: ['sport_bag', 'sport_apparel']
    },
    {
        _id: 'sport_bag',
        name: 'Sport Bag',
        description: 'sport的二级子分类.'
    },
    {
        _id: 'sport_apparel',
        name: 'Sport Apparel',
        description: 'sport的二级子分类.',
        sub_categories: ['sport_apparel_men', 'sport_apparel_women']
    },
    {
        _id: 'sport_apparel_men',
        name: 'Sport Apparel Men',
        description: 'sport的三级子分类.'
    },
    {
        _id: 'sport_apparel_women',
        name: 'Sport Apparel Women',
        description: 'sport的三级子分类.'
    }
];

2. 查询优化

为了查询特定分类下的所有商品,可以利用索引和聚合管道来实现高效查询。

示例代码

// 使用mongoose连接到MongoDB
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true });

// 定义分类模型
const CategorySchema = new mongoose.Schema({
    _id: String,
    name: String,
    description: String,
    sub_categories: [String],
});
const Category = mongoose.model('Category', CategorySchema);

// 查询sport分类下的所有商品
async function getProductsInCategory(categoryName) {
    const category = await Category.findOne({ name: categoryName });
    if (!category) return [];

    const pipeline = [
        {
            $lookup: {
                from: 'products', // 商品集合名
                localField: '_id',
                foreignField: 'category_id',
                as: 'products'
            }
        },
        { $unwind: '$products' },
        { $replaceRoot: { newRoot: '$products' } }
    ];

    if (category.sub_categories.length > 0) {
        pipeline.push({
            $match: { category_id: { $in: category.sub_categories } }
        });
    }

    const products = await Product.aggregate(pipeline);
    return products;
}

getProductsInCategory('Sport')
    .then(products => console.log(products))
    .catch(err => console.error(err));

通过这种方式,你可以更高效地管理和查询分类信息,同时保持数据的一致性和可扩展性。


  1. 你这模型建立的,太臃肿了,重复太多,提取自然就麻烦。
  2. 内容应该尽可能扁平,四级五级太搞笑了,不要关联太多。

####假设商品分类三级A->B->C,应该建立1个集合

[{
    _id: xxx,
    cat_name : 'xxx',
    cat_desc : 'xxx',
    A: 1
},
{
    _id: xxx,
    cat_name : 'xxx',
    cat_desc : 'xxx',
    A: 1,
    B: 1
},
{
    _id: xxx,
    cat_name : 'xxx',
    cat_desc : 'xxx',
    A: 1,
    B: 1,
    C: 1
},
...]

需要1级,只需要检索拥有A:1 需要2级,只需要检索拥有B:1 需要3级,只需要检索拥有C:1

####或者建立2个集合

cat集合
[{
    _id: xxx,
    cat_name : 'xxx',
    cat_desc : 'xxx',
},
...]
level集合
[{
    _id: xxx,
    level: 1,      // 第1级
    cat_id: [xxx, xxx, xxx, ...] 
},
{
    _id: xxx,
    level: 2,    // 第2级
    cat_id: [xxx, xxx, xxx, ...] 
},
{
    _id: xxx,
    level: 3,    // 第3级
    cat_id: [xxx, xxx, xxx, ...] 
}]

需要哪个等级只需要检索level对应集合和cat集合, 添加新值要同步level和cat

针对你提到的多维数组问题,确实会带来一些复杂性,尤其是在进行增删改操作时。MongoDB 提供了丰富的查询和更新能力,可以帮助我们更好地处理这种情况。

设计建议

  1. 扁平化设计:可以考虑将分类结构扁平化存储,每个分类作为一个独立的文档。这样每个文档都包含完整的路径信息(例如 path 字段),便于后续的查询和更新。

  2. 引用式设计:每个商品记录中只保存分类ID,分类信息存储在另一个集合中。这种方式的好处是便于管理分类,并且可以避免重复数据。

示例代码

假设我们选择扁平化设计的方式:

创建分类文档

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const CategorySchema = new Schema({
    name: String,
    desc: String,
    path: [String],
});

const Category = mongoose.model('Category', CategorySchema);

插入分类数据

async function insertCategories() {
    const categories = [
        { name: 'sport', desc: '第一个顶级分类.', path: [] },
        { name: 'sport_bag', desc: 'sport的二级子分类.', path: ['sport'] },
        { name: 'sport_apparel', desc: 'sport的二级子分类.', path: ['sport'] },
        { name: 'sport_apparel_men', desc: 'sport的三级子分类.', path: ['sport', 'sport_apparel'] },
        { name: 'sport_apparel_women', desc: 'sport的三级子分类.', path: ['sport', 'sport_apparel'] },
        { name: 'stationery', desc: '第二个顶级分类.', path: [] },
        { name: 'stationery_bag', desc: 'stationery的二级子分类.', path: ['stationery'] },
        { name: 'stationery_apparel', desc: 'stationery的二级子分类.', path: ['stationery'] },
        { name: 'stationery_apparel_men', desc: 'stationery的三级子分类.', path: ['stationery', 'stationery_apparel'] }
    ];

    await Category.insertMany(categories);
}

insertCategories().catch(console.error);

查询分类

async function findCategories() {
    const sportCategories = await Category.find({ path: { $all: ['sport'] } });
    console.log(sportCategories);
}

findCategories().catch(console.error);

通过这种方式,我们可以更方便地进行增删改操作,并且查询也更加高效。

回到顶部