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数据库应该怎么样设计才是最后理的????有类似的例子看吗?求指教!
针对你提到的问题,我们可以从几个方面来优化你的数据结构和查询方式。
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));
通过这种方式,你可以更高效地管理和查询分类信息,同时保持数据的一致性和可扩展性。
针对你提到的多维数组问题,确实会带来一些复杂性,尤其是在进行增删改操作时。MongoDB 提供了丰富的查询和更新能力,可以帮助我们更好地处理这种情况。
设计建议
-
扁平化设计:可以考虑将分类结构扁平化存储,每个分类作为一个独立的文档。这样每个文档都包含完整的路径信息(例如
path
字段),便于后续的查询和更新。 -
引用式设计:每个商品记录中只保存分类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);
通过这种方式,我们可以更方便地进行增删改操作,并且查询也更加高效。