首页  编辑  

使用对象解构和交叉类型简单优雅处理数据库结构和返回数据字段数量不一致的问题[原创]

Tags: /Node & JS/   Date Created:
在后端开发当中,我们可能需要处理如下的情况,数据库Schema定义了一些数据字段,但API返回的数据,可能需要去掉一些字段,或者又要临时多出一些字段返回给前端,如何能简单优化快捷地处理这种情况呢?

举例来说,数据库定义结构如下,Demo数据对象:
{
    id: ObjectId;
    name: string;
    value1: string;
    value2: string;
    created: Date;
    updated: Date;
}
现在后端 API 返回数据,可能出现两种情况:
  • 减少一些内部字段输出给前端,例如上述的 created, updated字段,是内部的日志时间戳使用,我们并不想给前端,那么需要去掉多余的字段。
  • 因为业务需要,临时在原来的字段基础上,再增加一些额外的信息输出。
对于上述的两种情况,我们可以考虑单独定义不同的 Response 数据结构来作为输出响应。这种方法,比较繁琐,例如我们有5个API,每个API在Demo的基础上可能都有一些不同的输出要求,如果分别定义的话,就有5个冗余的类定义出来,当然我们可以使用继承来实现,但也是非常繁琐,代码量比较大的。对于简单的差异化字段数量处理,我们可以使用对象解构技术来去掉不需要的字段,使用交叉类型来增加额外的字段。

对象解构

如果我们需要减少字段的输出,方法有几种,一种是在数据库查询的时候,使用投影技术,即不输出某些不需要的字段,但是很有可能数据的查询是其他模块处理的,我们无法使用投影技术。

以Demo对象为例,如果我们只想返回如下的数据解构:
{
    id: ObjectId;
    name: string;
    value1: string;
    value2: string;
}
我们可以使用对象解构技术,快速过滤不需要的字段: const { field1, field2, rest } = dbValue;
例如以Mongodb查询结果返回为例,下面的代码就能返回上述去掉 id, created, update 的精简信息了:
const list = this.demoRepository.find(condition, {}, {});
const ret = list.map( value => {
    const { _id, created, updated, rest } = (value as any).toObject();
    return rest;
});
return ret;

交叉类型

如果我们需要临时在现有数据DTO/POJO/DAO对象的基础上,增加一些额外的字段,又不想单独定义额外的DTO/POJO/DAO对象类,可以考虑使用交叉类型来实现。
例如:type TempDto = exist_dto & { [key: string]: object }
举例子来说,如果我们希望返回类似Demo的数据(多了address):
{
    id: ObjectId;
    name: string;
    value1: string;
    value2: string;
    created: Date;
    updated: Date;
    address: string;
    list: Array<string>;
}
我们可以用下面的方法来处理:
type Demo = {
    id: string;
    name: string;
    value1: string;
    value2: string;
    created: Date;
    updated: Date;
};
const demo: Demo = {
    id: "3B986461-45F9-E993-4785-01FA7360ED4B",
    name: "John Doe",
    value1: "Value 1",
    value2: "Value 2",
    created: new Date(),
    updated: new Date(),
};
​
const extendDemo : DemoData & {
   address: string,
    list: Array<string>,
} = {
    ...demo,
    "address": "aaaa",
    list: ["Item 1", "Item 2", "Item 3"],
}
console.log(extendDemo);