如何标准化定义含国家-城市关联的数据集Schema以支持级联下拉生成
问题描述
现有人员-国家-城市数据集示例:
[ { "person": "tom", "countryName": "USA", "cityName": "newyork" }, { "person": "lee", "countryName": "China", "cityName": "beijing" }, // ... 更多数据 ]
需通过标准Schema(如JSON Schema)定义该数据集并存储至MongoDB,当前拟用的Schema如下,但未定义countryName与cityName的级联关联(每个国家对应专属城市列表):
[ { "name": "personName", "type": "String" }, { "name": "countryName", "type": "String", "options": ["USA", "CHINA"] }, { "name": "cityName", "type": "String", "options": ["newYork", "chicago", "beijing"...] } ]
期望的国家-城市关联映射示例:
[ { "countryName": "USA", "children": ["newYork", "chicago", ...] }, { "countryName": "China", "children": ["beijing", "shanghai", ...] }, // ... 更多映射 ]
需要标准化修改Schema,建立二者关联,使UI生成器可识别该关系并自动生成国家选择后联动对应城市列表的级联下拉过滤器。
解决方案
1. 基于JSON Schema的标准化定义(推荐用于UI生成器识别)
JSON Schema支持通过自定义扩展关键字和校验规则实现级联关联,既符合标准又能被UI工具识别:
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "array", "items": { "type": "object", "properties": { "person": { "type": "string", "title": "人员名称" }, "countryName": { "type": "string", "title": "国家", "enum": ["USA", "China"] }, "cityName": { "type": "string", "title": "城市" } }, "required": ["person", "countryName", "cityName"], // 自定义扩展字段:存储国家-城市级联映射,供UI生成器读取 "x-country-city-map": { "USA": ["newYork", "chicago", "losAngeles"], "China": ["beijing", "shanghai", "guangzhou"] }, // 可选:添加数据一致性校验,确保城市属于所选国家 "allOf": [ { "if": { "properties": { "countryName": { "const": "USA" } } }, "then": { "properties": { "cityName": { "enum": ["newYork", "chicago", "losAngeles"] } } } }, { "if": { "properties": { "countryName": { "const": "China" } } }, "then": { "properties": { "cityName": { "enum": ["beijing", "shanghai", "guangzhou"] } } } } ] } }
x-country-city-map是约定的自定义关键字,UI生成器可直接读取该字段来构建级联下拉逻辑。allOf+if/then规则用于校验数据,确保存储的城市与国家匹配,避免脏数据。
2. 适配MongoDB的Schema设计
方式一:单集合带元数据(适合小型数据集)
直接在Schema中存储级联映射元数据,同时添加校验逻辑:
// 使用Mongoose定义MongoDB Schema const personLocationSchema = new mongoose.Schema({ person: { type: String, required: true }, countryName: { type: String, required: true, enum: ["USA", "China"] }, cityName: { type: String, required: true } }, { // 存储级联映射元数据,供UI生成器读取 _meta: { countryCityMap: { "USA": ["newYork", "chicago", "losAngeles"], "China": ["beijing", "shanghai", "guangzhou"] } } }); // 前置校验:确保城市属于所选国家 personLocationSchema.pre('save', function(next) { const allowedCities = this.schema.options._meta.countryCityMap[this.countryName]; if (!allowedCities || !allowedCities.includes(this.cityName)) { return next(new Error(`城市${this.cityName}不属于国家${this.countryName}`)); } next(); });
方式二:拆分集合(适合大型/需独立维护的数据集)
将国家-城市映射单独存储为集合,人员集合通过关联字段引用:
国家集合Schema
const countrySchema = new mongoose.Schema({ name: { type: String, required: true, unique: true }, cities: [{ type: String, required: true }] }); const Country = mongoose.model('Country', countrySchema);
人员集合Schema
const personSchema = new mongoose.Schema({ name: { type: String, required: true }, countryName: { type: String, required: true, ref: 'Country' // 关联国家集合 }, cityName: { type: String, required: true } }); // 校验城市属于关联国家 personSchema.pre('save', async function(next) { const country = await Country.findOne({ name: this.countryName }); if (!country || !country.cities.includes(this.cityName)) { return next(new Error(`城市${this.cityName}不属于国家${this.countryName}`)); } next(); });
这种方式下,UI生成器可先从Country集合拉取完整的国家-城市映射,再实现级联下拉。
3. 让UI生成器识别级联关系的核心要点
无论采用哪种方案,关键是明确暴露国家-城市的映射关系:
- 若用JSON Schema,通过自定义扩展关键字(如
x-country-city-map)约定映射存储位置,UI工具按约定读取。 - 若用MongoDB,将映射存储在Schema元数据或独立集合中,UI生成器通过查询元数据/集合获取映射规则。
内容的提问来源于stack exchange,提问作者user824624
相关产品推荐
相关产品推荐

