转载

[译]JSON数据范式化(normalizr)

开发复杂的应用时,不可避免会有一些数据相互引用。建议你尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同数据相互引用时通过 ID 来查找。把  应用的 state 想像成数据库 。这种方法在  normalizr 文档里有详细阐述。

normalizr :将嵌套的JSON格式扁平化,方便被Redux利用;

目标

我们的目标是将:

[{   id: 1,   title: 'Some Article',   author: {     id: 1,     name: 'Dan'   } }, {   id: 2,   title: 'Other Article',   author: {     id: 1,     name: 'Dan'   } }] 
  • 数组的每个对象都糅合了三个维度  文章  、  作者
  • 按照数据范式,应当将这两个维度拆分出来,两者的联系通过id关联起来即可

我们描述上述的结构: - 返回的是一个数组(array) - 数组的对象中包含另外一个schema —— user

应该比较合理的,应该是转换成:

{   result: [1, 2],   entities: {     articles: {       1: {         id: 1,         title: 'Some Article',         author: 1       },       2: {         id: 2,         title: 'Other Article',         author: 1       }     },     users: {       1: {         id: 1,         name: 'Dan'       }     }   } } 

如何使用

观看示例最好的,就是官方的测试文件: https://github.com/gaearon/normalizr/blob/master/test/index.js

先引入 normalizr

import { normalize, Schema, arrayOf } from 'normalizr';   

定义 schema

    var article = new Schema('articles'),         user = new Schema('users'),         collection = new Schema('collections'),         feedSchema,         input; 

定义规则:

    article.define({       author: user,       collections: arrayOf(collection)     });      collection.define({       curator: user     });      feedSchema = {       feed: arrayOf(article)     }; 

测试:

    input = {       feed: [{         id: 1,         title: 'Some Article',         author: {           id: 3,           name: 'Mike Persson'         },         collections: [{           id: 1,           title: 'Awesome Writing',           curator: {             id: 4,             name: 'Andy Warhol'           }         }, {           id: 7,           title: 'Even Awesomer',           curator: {             id: 100,             name: 'T.S. Eliot'           }         }]       }, {         id: 2,         title: 'Other Article',         collections: [{           id: 2,           title: 'Neverhood',           curator: {             id: 120,             name: 'Ada Lovelace'           }         }],         author: {           id: 2,           name: 'Pete Hunt'         }       }]     };      Object.freeze(input);      normalize(input, feedSchema).should.eql({       result: {         feed: [1, 2]       },       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             author: 3,             collections: [1, 7]           },           2: {             id: 2,             title: 'Other Article',             author: 2,             collections: [2]           }         },         collections: {           1: {             id: 1,             title: 'Awesome Writing',             curator: 4           },           2: {             id: 2,             title: 'Neverhood',             curator: 120           },           7: {             id: 7,             title: 'Even Awesomer',             curator: 100           }         },         users: {           2: {             id: 2,             name: 'Pete Hunt'           },           3: {             id: 3,             name: 'Mike Persson'           },           4: {             id: 4,             name: 'Andy Warhol'           },           100: {             id: 100,             name: 'T.S. Eliot'           },           120: {             id: 120,             name: 'Ada Lovelace'           }         }       }     }); 

优势

假定请求 /articles 返回的数据的schema如下:

articles: article*  article: {     author: user,   likers: user*   primary_collection: collection?   collections: collection* }  collection: {     curator: user } 

如果不做范式化,store需要事先知道API的各种结构,比如 UserStore 会包含很多样板代码来获取新用户,诸如下面那样:

  switch (action.type) {   case ActionTypes.RECEIVE_USERS:     mergeUsers(action.rawUsers);     break;    case ActionTypes.RECEIVE_ARTICLES:     action.rawArticles.forEach(rawArticle => {       mergeUsers([rawArticle.user]);       mergeUsers(rawArticle.likers);        mergeUsers([rawArticle.primaryCollection.curator]);       rawArticle.collections.forEach(rawCollection => {         mergeUsers(rawCollection.curator);       });     });      UserStore.emitChange();     break;   } 

store表示累觉不爱啊!! 每个store都要对返回的 进行各种foreach 才能获取想要的数据。

来一个范式吧:

const article = new Schema('articles');   const user = new Schema('users');  article.define({     author: user,   contributors: arrayOf(user),   meta: {     likes: arrayOf({       user: user     })   } });  // ...  const json = getArticleArray();   const normalized = normalize(json, arrayOf(article));   

经过范式整顿之后,你爱理或者不爱理,users对象总是在 action.entities.users 中:

  const { action } = payload;    if (action.response && action.response.entities && action.response.entities.users) {     mergeUsers(action.response.entities.users);     UserStore.emitChange();     break;   } 

更多示例(来自测试文件)

规范化单个文件

    var article = new Schema('articles'),         input;      input = {       id: 1,       title: 'Some Article',       isFavorite: false     };      Object.freeze(input);      normalize(input, article).should.eql({       result: 1,       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             isFavorite: false           }         }       }     }); 

规范化内嵌对象,并删除额外key

有时候后端接口会返回很多额外的字段,甚至会有重复的字段;比如下方示例中 typeId 和  type.id 是重复的;注意方法中 形参 key 是经过 artcle.define 定义过的。

    var article = new Schema('articles'),         type = new Schema('types'),         input;      // 定义内嵌规则     article.define({       type: type     });      input = {       id: 1,       title: 'Some Article',       isFavorite: false,       typeId: 1,       type: {         id: 1,       }     };      Object.freeze(input);      // assignEntity删除后端返回额外数据的     var options = {       assignEntity: function(obj, key, val) {         obj[key] = val;         delete obj[key + 'Id'];       }     };      normalize(input, article, options).should.eql({       result: 1,       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             isFavorite: false,             type: 1           }         },         types: {           1: {             id: 1           }         }       }     }); 

添加额外数据

和上个示例相反的是, mergeIntoEntity 用于将多份同质数据不同信息融合到一起,用于解决冲突。

下方示例中, author 和  reviewer 是同一个人,只是前者留下的联系方式是手机,后者留下的联系方式是邮箱,但无论如何都是同一个人;

此时就可以使用 mergeIntoEntity 将两份数据融合到一起;(注意这里是用  valueOf 规则 )

    var author = new Schema('authors'),         input;      input = {       author: {         id: 1,         name: 'Ada Lovelace',         contact: {           phone: '555-0100'         }       },       reviewer: {         id: 1,         name: 'Ada Lovelace',         contact: {           email: 'ada@lovelace.com'         }       }     }      Object.freeze(input);      var options = {       mergeIntoEntity: function(entityA, entityB, entityKey) {         var key;          for (key in entityB) {           if (!entityB.hasOwnProperty(key)) {             continue;           }            if (!entityA.hasOwnProperty(key) || isEqual(entityA[key], entityB[key])) {             entityA[key] = entityB[key];             continue;           }            if (isObject(entityA[key]) && isObject(entityB[key])) {             merge(entityA[key], entityB[key])             continue;           }            console.warn('Unequal data!');         }       }     };      normalize(input, valuesOf(author), options).should.eql({       result: {         author: 1,         reviewer: 1       },       entities: {         authors: {           1: {             id: 1,             name: 'Ada Lovelace',             contact: {               phone: '555-0100',               email: 'ada@lovelace.com'             }           }         }       }     }); 

按指定的属性规范化

有时候对象没有 id 属性,或者我们并不想按  id 属性规范化,可以使用  idAttribute 指定;

下面的例子,就是使用 slug 作为规范化的key:

  var article = new Schema('articles', { idAttribute: 'slug' }),         input;      input = {       id: 1,       slug: 'some-article',       title: 'Some Article',       isFavorite: false     };      Object.freeze(input);      normalize(input, article).should.eql({       result: 'some-article',       entities: {         articles: {           'some-article': {             id: 1,             slug: 'some-article',             title: 'Some Article',             isFavorite: false           }         }       }     }); 

创建自定义的属性

有时候想自己创建一个key,虽然今天和去年创建的文章名称都是 Happy ,但明显是不一样的,为了按时间区分出来,可以  使用自定义函数生成想要的key

    function makeSlug(article) {       var posted = article.posted,           title = article.title.toLowerCase().replace(' ', '-');        return [title, posted.year, posted.month, posted.day].join('-');     }      var article = new Schema('articles', { idAttribute: makeSlug }),         input;      input = {       id: 1,       title: 'Some Article',       isFavorite: false,       posted: {         day: 12,         month: 3,         year: 1983       }     };      Object.freeze(input);      normalize(input, article).should.eql({       result: 'some-article-1983-3-12',       entities: {         articles: {           'some-article-1983-3-12': {             id: 1,             title: 'Some Article',             isFavorite: false,             posted: {               day: 12,               month: 3,               year: 1983             }           }         }       }     }); 

规范化数组

后端返回的数据往往是一串数组居多,此时规范化起到很大的作用,规范化的同时将数据压缩了一遍;

   var article = new Schema('articles'),         input;      input = [{       id: 1,       title: 'Some Article'     }, {       id: 2,       title: 'Other Article'     }];      Object.freeze(input);      normalize(input, arrayOf(article)).should.eql({       result: [1, 2],       entities: {         articles: {           1: {             id: 1,             title: 'Some Article'           },           2: {             id: 2,             title: 'Other Article'           }         }       }     }); 

抽取多个schema

上面讲的情形比较简单,只涉及抽出结果是单个schema的情形;现实中,你往往想抽象出多个schema,比如下方,我想抽离出 tutorials (教程) 和 articles (文章)两个 schema,此时需要  通过 schemaAttribute 选项指定区分这两个 schema 的字段

    var article = new Schema('articles'),         tutorial = new Schema('tutorials'),         articleOrTutorial = { articles: article, tutorials: tutorial },         input;      input = [{       id: 1,       type: 'articles',       title: 'Some Article'     }, {       id: 1,       type: 'tutorials',       title: 'Some Tutorial'     }];      Object.freeze(input);      normalize(input, arrayOf(articleOrTutorial, { schemaAttribute: 'type' })).should.eql({       result: [         {id: 1, schema: 'articles'},         {id: 1, schema: 'tutorials'}       ],       entities: {         articles: {           1: {             id: 1,             type: 'articles',             title: 'Some Article'           }         },         tutorials: {           1: {             id: 1,             type: 'tutorials',             title: 'Some Tutorial'           }         }       }     }); 

这个示例中,虽然文章的id都是1,但很明显它们是不同的文章,因为一篇是普通文章,一篇是教程文章;因此要按schema维度抽离数据;

这里的 arrayOf(articleOrTutorial) 中的  articleOrTutorial 是包含多个属性的对象,这表示  input 应该是  articleOrTutorial 中的一种情况;

有时候原始数据属性 和 我们定义的有些差别,此时可以将 schemaAttribute 的值设成函数,将原始属性经过适当加工;比如原始属性是 tutorial , 而抽离出的 schema 名字为  tutorials ,相差一个 s

    function guessSchema(item) {       return item.type + 's';     }      var article = new Schema('articles'),         tutorial = new Schema('tutorials'),         articleOrTutorial = { articles: article, tutorials: tutorial },         input;      input = [{       id: 1,       type: 'article',       title: 'Some Article'     }, {       id: 1,       type: 'tutorial',       title: 'Some Tutorial'     }];      Object.freeze(input);      normalize(input, arrayOf(articleOrTutorial, { schemaAttribute: guessSchema })).should.eql({       result: [         { id: 1, schema: 'articles' },         { id: 1, schema: 'tutorials' }       ],       entities: {         articles: {           1: {             id: 1,             type: 'article',             title: 'Some Article'           }         },         tutorials: {           1: {             id: 1,             type: 'tutorial',             title: 'Some Tutorial'           }         }       }     }); 

上述是数组情况,针对普通的对象也是可以的,将规则 改成 valueOf 即可:

   var article = new Schema('articles'),         tutorial = new Schema('tutorials'),         articleOrTutorial = { articles: article, tutorials: tutorial },         input;      input = {       one: {         id: 1,         type: 'articles',         title: 'Some Article'       },       two: {         id: 2,         type: 'articles',         title: 'Another Article'       },       three: {         id: 1,         type: 'tutorials',         title: 'Some Tutorial'       }     };      Object.freeze(input);      normalize(input, valuesOf(articleOrTutorial, { schemaAttribute: 'type' })).should.eql({       result: {         one: {id: 1, schema: 'articles'},         two: {id: 2, schema: 'articles'},         three: {id: 1, schema: 'tutorials'}       },       entities: {         articles: {           1: {             id: 1,             type: 'articles',             title: 'Some Article'           },           2: {             id: 2,             type: 'articles',             title: 'Another Article'           }         },         tutorials: {           1: {             id: 1,             type: 'tutorials',             title: 'Some Tutorial'           }         }       }     }); 

schemaAttribute 是函数的情况就不列举了,和上述一致;

规范化内嵌情形

上面的对象比较简单,原本就是扁平化的;如果对象格式稍微复杂一些,比如每篇文章有多个作者的情形。此时需要使用 define 事先声明 schema 之间的层级关系:

    var article = new Schema('articles'),         user = new Schema('users'),         input;      article.define({       author: user     });      input = {       id: 1,       title: 'Some Article',       author: {         id: 3,         name: 'Mike Persson'       }     };      Object.freeze(input);      normalize(input, article).should.eql({       result: 1,       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             author: 3           }         },         users: {           3: {             id: 3,             name: 'Mike Persson'           }         }       }     }); 

上面是不是觉得简单了?那么给你一个比较复杂的情形,万变不离其宗。我们最终想抽离出 articlesusers 以及  collections 这三个 schema,所以只要定义这三个schema就行了,

然后使用 define 方法声明这三个schema之间千丝万缕的关系;

最外层的feed只是属性,并不需要定义;

    var article = new Schema('articles'),         user = new Schema('users'),         collection = new Schema('collections'),         feedSchema,         input;      article.define({       author: user,       collections: arrayOf(collection)     });      collection.define({       curator: user     });      feedSchema = {       feed: arrayOf(article)     };      input = {       feed: [{         id: 1,         title: 'Some Article',         author: {           id: 3,           name: 'Mike Persson'         },         collections: [{           id: 1,           title: 'Awesome Writing',           curator: {             id: 4,             name: 'Andy Warhol'           }         }, {           id: 7,           title: 'Even Awesomer',           curator: {             id: 100,             name: 'T.S. Eliot'           }         }]       }, {         id: 2,         title: 'Other Article',         collections: [{           id: 2,           title: 'Neverhood',           curator: {             id: 120,             name: 'Ada Lovelace'           }         }],         author: {           id: 2,           name: 'Pete Hunt'         }       }]     };      Object.freeze(input);      normalize(input, feedSchema).should.eql({       result: {         feed: [1, 2]       },       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             author: 3,             collections: [1, 7]           },           2: {             id: 2,             title: 'Other Article',             author: 2,             collections: [2]           }         },         collections: {           1: {             id: 1,             title: 'Awesome Writing',             curator: 4           },           2: {             id: 2,             title: 'Neverhood',             curator: 120           },           7: {             id: 7,             title: 'Even Awesomer',             curator: 100           }         },         users: {           2: {             id: 2,             name: 'Pete Hunt'           },           3: {             id: 3,             name: 'Mike Persson'           },           4: {             id: 4,             name: 'Andy Warhol'           },           100: {             id: 100,             name: 'T.S. Eliot'           },           120: {             id: 120,             name: 'Ada Lovelace'           }         }       }     }); 

内嵌+数组倾斜

   var article = new Schema('articles'),         tutorial = new Schema('tutorials'),         articleOrTutorial = { articles: article, tutorials: tutorial },         user = new Schema('users'),         collection = new Schema('collections'),         feedSchema,         input;      article.define({       author: user,       collections: arrayOf(collection)     });      tutorial.define({       author: user,       collections: arrayOf(collection)     });      collection.define({       curator: user     });      feedSchema = {       feed: arrayOf(articleOrTutorial, { schemaAttribute: 'type' })     };      input = {       feed: [{         id: 1,         type: 'articles',         title: 'Some Article',         author: {           id: 3,           name: 'Mike Persson'         },         collections: [{           id: 1,           title: 'Awesome Writing',           curator: {             id: 4,             name: 'Andy Warhol'           }         }, {           id: 7,           title: 'Even Awesomer',           curator: {             id: 100,             name: 'T.S. Eliot'           }         }]       }, {         id: 1,         type: 'tutorials',         title: 'Some Tutorial',         collections: [{           id: 2,           title: 'Neverhood',           curator: {             id: 120,             name: 'Ada Lovelace'           }         }],         author: {           id: 2,           name: 'Pete Hunt'         }       }]     };      Object.freeze(input);      normalize(input, feedSchema).should.eql({       result: {         feed: [           { id: 1, schema: 'articles' },           { id: 1, schema: 'tutorials' }         ]       },       entities: {         articles: {           1: {             id: 1,             type: 'articles',             title: 'Some Article',             author: 3,             collections: [1, 7]           }         },         tutorials: {           1: {             id: 1,             type: 'tutorials',             title: 'Some Tutorial',             author: 2,             collections: [2]           }         },         collections: {           1: {             id: 1,             title: 'Awesome Writing',             curator: 4           },           2: {             id: 2,             title: 'Neverhood',             curator: 120           },           7: {             id: 7,             title: 'Even Awesomer',             curator: 100           }         },         users: {           2: {             id: 2,             name: 'Pete Hunt'           },           3: {             id: 3,             name: 'Mike Persson'           },           4: {             id: 4,             name: 'Andy Warhol'           },           100: {             id: 100,             name: 'T.S. Eliot'           },           120: {             id: 120,             name: 'Ada Lovelace'           }         }       }     }); 

内嵌 + 对象(再内嵌)

看到下面的 valuesOf(arrayOf(user)) 了没有,它表示该属性是一个对象,对象里面各个数组值是 User对象数组;

    var article = new Schema('articles'),         user = new Schema('users'),         feedSchema,         input;      article.define({       collaborators: valuesOf(arrayOf(user))     });      feedSchema = {       feed: arrayOf(article),       suggestions: valuesOf(arrayOf(article))     };      input = {       feed: [{         id: 1,         title: 'Some Article',         collaborators: {           authors: [{             id: 3,             name: 'Mike Persson'           }],           reviewers: [{             id: 2,             name: 'Pete Hunt'           }]         }       }, {         id: 2,         title: 'Other Article',         collaborators: {           authors: [{             id: 2,             name: 'Pete Hunt'           }]         }       }, {         id: 3,         title: 'Last Article'       }],       suggestions: {         1: [{           id: 2,           title: 'Other Article',           collaborators: {             authors: [{               id: 2,               name: 'Pete Hunt'             }]           }         }, {           id: 3,           title: 'Last Article'         }]       }     };      Object.freeze(input);      normalize(input, feedSchema).should.eql({       result: {         feed: [1, 2, 3],         suggestions: {           1: [2, 3]         }       },       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             collaborators: {               authors: [3],               reviewers: [2]             }           },           2: {             id: 2,             title: 'Other Article',             collaborators: {               authors: [2]             }           },           3: {             id: 3,             title: 'Last Article'           }         },         users: {           2: {             id: 2,             name: 'Pete Hunt'           },           3: {             id: 3,             name: 'Mike Persson'           }         }       }     }); 

还有更加复杂的,这次用上 valuesOf(userOrGroup, { schemaAttribute: 'type' }) 了:

    var article = new Schema('articles'),         user = new Schema('users'),         group = new Schema('groups'),         userOrGroup = { users: user, groups: group },         feedSchema,         input;      article.define({       collaborators: valuesOf(userOrGroup, { schemaAttribute: 'type' })     });      feedSchema = {       feed: arrayOf(article),       suggestions: valuesOf(arrayOf(article))     };      input = {       feed: [{         id: 1,         title: 'Some Article',         collaborators: {           author: {             id: 3,             type: 'users',             name: 'Mike Persson'           },           reviewer: {             id: 2,             type: 'groups',             name: 'Reviewer Group'           }         }       }, {         id: 2,         title: 'Other Article',         collaborators: {           author: {             id: 2,             type: 'users',             name: 'Pete Hunt'           }         }       }, {         id: 3,         title: 'Last Article'       }],       suggestions: {         1: [{           id: 2,           title: 'Other Article'         }, {           id: 3,           title: 'Last Article'         }]       }     };      Object.freeze(input);      normalize(input, feedSchema).should.eql({       result: {         feed: [1, 2, 3],         suggestions: {           1: [2, 3]         }       },       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             collaborators: {               author: { id: 3, schema: 'users' },               reviewer: { id: 2, schema: 'groups' }             }           },           2: {             id: 2,             title: 'Other Article',             collaborators: {               author: { id: 2, schema: 'users' }             }           },           3: {             id: 3,             title: 'Last Article'           }         },         users: {           2: {             id: 2,             type: 'users',             name: 'Pete Hunt'           },           3: {             id: 3,             type: 'users',             name: 'Mike Persson'           }         },         groups: {           2: {             id: 2,             type: 'groups',             name: 'Reviewer Group'           }         }       }     }); 

递归调用

比如某某人关注了另外的人, 用户 写了一系列文章,该文章  被其他用户 订阅就是这种情况:

    var article = new Schema('articles'),         user = new Schema('users'),         collection = new Schema('collections'),         feedSchema,         input;      user.define({       articles: arrayOf(article)     });      article.define({       collections: arrayOf(collection)     });      collection.define({       subscribers: arrayOf(user)     });      feedSchema = {       feed: arrayOf(article)     };      input = {       feed: [{         id: 1,         title: 'Some Article',         collections: [{           id: 1,           title: 'Awesome Writing',           subscribers: [{             id: 4,             name: 'Andy Warhol',             articles: [{               id: 1,               title: 'Some Article'             }]           }, {             id: 100,             name: 'T.S. Eliot',             articles: [{               id: 1,               title: 'Some Article'             }]           }]         }, {           id: 7,           title: 'Even Awesomer',           subscribers: [{             id: 100,             name: 'T.S. Eliot',             articles: [{               id: 1,               title: 'Some Article'             }]           }]         }]       }]     };      Object.freeze(input);      normalize(input, feedSchema).should.eql({       result: {         feed: [1]       },       entities: {         articles: {           1: {             id: 1,             title: 'Some Article',             collections: [1, 7]           }         },         collections: {           1: {             id: 1,             title: 'Awesome Writing',             subscribers: [4, 100]           },           7: {             id: 7,             title: 'Even Awesomer',             subscribers: [100]           }         },         users: {           4: {             id: 4,             name: 'Andy Warhol',             articles: [1]           },           100: {             id: 100,             name: 'T.S. Eliot',             articles: [1]           }         }       }     }); 

上面还算好的,有些schema直接就递归声明了,比如 儿女和父母 的关系:

    var user = new Schema('users'),         input;      user.define({       parent: user     });      input = {       id: 1,       name: 'Andy Warhol',       parent: {         id: 7,         name: 'Tom Dale',         parent: {           id: 4,           name: 'Pete Hunt'         }       }     };      Object.freeze(input);      normalize(input, user).should.eql({       result: 1,       entities: {         users: {           1: {             id: 1,             name: 'Andy Warhol',             parent: 7           },           7: {             id: 7,             name: 'Tom Dale',             parent: 4           },           4: {             id: 4,             name: 'Pete Hunt'           }         }       }     }); 

自动merge属性

在一个数组里面,如果id属性一致,会自动抽取并合属性成一个:

    var writer = new Schema('writers'),         book = new Schema('books'),         schema = arrayOf(writer),         input;      writer.define({       books: arrayOf(book)     });      input = [{       id: 3,       name: 'Jo Rowling',       isBritish: true,       location: {         x: 100,         y: 200,         nested: ['hello', {           world: true         }]       },       books: [{         id: 1,         soldWell: true,         name: 'Harry Potter'       }]     }, {       id: 3,       name: 'Jo Rowling',       bio: 'writer',       location: {         x: 100,         y: 200,         nested: ['hello', {           world: true         }]       },       books: [{         id: 1,         isAwesome: true,         name: 'Harry Potter'       }]     }];      normalize(input, schema).should.eql({       result: [3, 3],       entities: {         writers: {           3: {             id: 3,             isBritish: true,             name: 'Jo Rowling',             bio: 'writer',             books: [1],             location: {               x: 100,               y: 200,               nested: ['hello', {                 world: true               }]             }           }         },         books: {           1: {             id: 1,             isAwesome: true,             soldWell: true,             name: 'Harry Potter'           }         }       }     }); 

如果合并过程中有冲突会有提示,并自动剔除冲突的属性;比如下方同一个作者写的书,一个对象里描述“卖得好”,而在另外一个对象里却描述“卖得差”,明显是有问题的:

    var writer = new Schema('writers'),         book = new Schema('books'),         schema = arrayOf(writer),         input;      writer.define({       books: arrayOf(book)     });      input = [{       id: 3,       name: 'Jo Rowling',       books: [{         id: 1,         soldWell: true,         name: 'Harry Potter'       }]     }, {       id: 3,       name: 'Jo Rowling',       books: [{         id: 1,         soldWell: false,         name: 'Harry Potter'       }]     }];      var warnCalled = false,         realConsoleWarn;      function mockWarn() {       warnCalled = true;     }      realConsoleWarn = console.warn;     console.warn = mockWarn;      normalize(input, schema).should.eql({       result: [3, 3],       entities: {         writers: {           3: {             id: 3,             name: 'Jo Rowling',             books: [1]           }         },         books: {           1: {             id: 1,             soldWell: true,             name: 'Harry Potter'           }         }       }     });      warnCalled.should.eq(true);     console.warn = realConsoleWarn; 

传入不存在的schema规范

如果应用的schma规范不存在,你还传入,就会创建一个新的父属性:

    var writer = new Schema('writers'),         schema = writer,         input;     input = {       id: 'constructor',       name: 'Constructor',       isAwesome: true     };      normalize(input, schema).should.eql({       result: 'constructor',       entities: {         writers: {           constructor: {             id: 'constructor',             name: 'Constructor',             isAwesome: true           }         }       }
原文  https://yq.aliyun.com/articles/3168
正文到此结束
Loading...