问题描述
如何使用查询字符串(反)序列化嵌套字典?我已经查看了关于如何序列化嵌套对象的 other posts,但我找不到在反序列化时保留原始字典层次结构/布局的便捷方法。
假设我有以下输入:
const params = {
id: 1,filters: {
price: {
min: 101,max: 300
}
},sorters: {
sortBy: 'price',order: 'desc'
}
}
如何使用查询字符串来回转换?
我可以使用 jquery $.param
将其转换为查询字符串,但是当我尝试将其转换回原始 params
时,它是不正确的:
Object.fromEntries(new URLSearchParams($.param(params)))
输出:
{
"id": "1","filters[price][min]": "101","filters[price][max]": "300","sorters[sortBy]": "price","sorters[order]": "desc"
}
解决方法
正如在聊天中所讨论的 - 似乎您希望能够在客户端和服务器上使用相同的对象图表示查询标准(这是合理的) - 好消息是,因为您的对象图具有一致的设计,您可以编写一个简单的函数,将图形序列化为更简洁的 URI 查询字符串表示 多余的参数名称前缀或浪费的大括号/冒号/引号空间...
总结:
-
params
对象中唯一的可变参数部分是filters:
子对象。id
和sorters
部分具有固定布局 - 这意味着filters[]
部分是不必要的。
所以:
const params = {
id: 1,filters: {
price: {
min: 101,max: 300
}
},sorters: {
sortBy: 'price',order: 'desc'
}
}
可以序列化为:
id=1&price_min=101&price_max=300&sortBy=price&dir=desc
这里有一些逻辑可以将这样的查询字符串反序列化回您最初拥有的 params
对象:
const queryObject = {
id: null,filter: {},sorters: {}
};
const qs = new URLSearchParams( "id=1&price_min=101&price_max=300&sortBy=price&dir=desc" );
for(const [key,value] of qs) {
if( key === 'id' ) queryObject.id = value;
else if( key === 'sortBy' ) queryObject.sorters.sortBy = value;
else if( key === 'dir' ) queryObject.sorters.order = value;
else {
if( key.endsWith("_min") || key.endsWith("_max") ) {
const name = key.substring(0,key.indexof("_"));
if( !name in queryObject.filters ) {
queryObject.filters[name] = {};
}
if( key.endsWith("_min") ) {
queryObject.filters[name].min = value;
} else {
queryObject.filters[name].max = value;
}
}
else {
queryObject.filters[key] = value;
}
}
}
将 params
序列化为 URLSearchParams
也很简单:
const qs = new URLSearchParams();
if( 'id' in params ) qs.set('id',params['id']);
if( 'sortBy' in params.sorters ) qs.set('sortBy',params.sorters.sortBy);
if( 'order' in params.sorters ) qs.set('dir',params.sorters.order);
for( const key of params.filters ) {
if( typeof(params.filters[key] === 'object') {
qs.set(key + '_min') = params.filters[key].min;
qs.set(key + '_max') = params.filters[key].max;
}
else {
qs.set(key) = params.filters[key];
}
}