版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、开发向导上次更改时间2015/12/08创立一个帐号首先,注册并登录Wilddog账号,进入控制面板。然后,在控制面板中,添加一个新的应用。你会得到一个应用的URLs:/<appld>.wilddogio/。你可以把这个URL理解为云端数据库的地址。安装Wilddog使用JavascriptSDK非常简单。你只需在HTML文件中参加一个script标签。<scriptsrc=></script>Wilddognode.js版API与javascript版完全一样。Wilddog客户端在Node.js上运行非常简单,首先需要通过npm安装Wilddog模块$n
2、pminstallwilddog-save使用require在你的应用中使用wilddogvarWilddog=require("wilddog");Typescript用户typescript调用原生js需要有一个.d.ts文件。在这里可以找到在Ionic工程中使用Ionic是一个利用html5开发混合手机APP的前端SDK,由于Ionic使用Angular,所以开发者在开发IonicAPP时可以使用wild-angular来简化wilddog的一些操作。如今我们可以使用Ionic提供的命令行命令来安装Ionic:$npminstall-gionic假设在Mac电脑开发应
3、用并且希望运行在ios设备上,需要先安装XCode,然后用npm安装ios-sim:$npminstall-gios-sim如今我们可以使用Ionic的命令行工具来创立一个空白的Ionic应用模板:$ionicstartmyappblank使用下面的命令行可以告诉Ionic我们的应用要适配ios和Android:$ionicplatformaddios$ionicplatformaddandroid集成Wilddog:在html文件中,在引入自己的app.js文件之前,我们引入Wilddog和wild-angular作为依赖,<!-Wilddog-><scriptsrc=&g
4、t;</script><!-wild-angular-><scriptsrc="s:></script>在自己的app.js文件中把Wilddog作为依赖注入到我们的module中:angular.module("starter","ionic","wilddog")如今我们就可以使用wild-angular的$wilddogObject、$wilddogArray、$wilddogAuth来对数据进展操作了。提示和建议1,我们建议你直接使用野狗官方提供的SDK地址。这样,你将
5、无需更新任何代码,即可获得更新。2,wilddog.js是经过大量测试的RELEASE版本。3,野狗全站均支持Spdy3.1和Gzip压缩。我们正在尝试更高的压缩比,例如SDCH,2来进一步提升静态资源加载速度。4,不用担忧s的性能。我们对s进展了极致的优化。野狗的官网,直到windows.onload事件触发,也只花费了不到500mso2.理解数据数据是一棵JSON树所有的数据都存储在各个JSON对象中,没有任何表的概念。当你把数据添加到这棵json树中,这些数据就变成这棵树的子树。比方,我们在users/mchen下增加widget后,我们的数据是这样的"users":
6、"mchen":"friends":"brinchen":true,"name":"MaryChen",/新数据节点会增加在已经存在的JSON树中"widgets":"one":true,"three":true,"brinchen":.,"hmadi":.创立一个Wilddog对象引用在html中读写wilddog数据,需要创立一个Wilddog对象引用,要操作和同步哪些数据取决于创立Wildd
7、og对象引用时传入的URLnewWilddog('s:/<appId>.wilddogio/web/data');创立一个Wilddog引用并不是直接访问这个URL,或创立一个连接。数据直到需要的时候才会传输。一旦这个数据被查询,这个数据会一直与效劳端保持一致。你可以直接访问一个子节点:newWilddog('s:<appId>.wilddogio/web/data/users/mchen/name');你还可以通过child接口进展相对途径访问:varrootRef=newWilddog('s:/<appId>.wi
8、lddogio/web/data');rootRef.child('users/mchen/name');Wilddog中的数组Wilddog并不天然支持数组,当我们想存数组时,我们把数组变成对象/原始数据'hello','world'/存储后的新数据0:'hello',1:'world'需要注意的是,假设某节点的所有子节点的key都是整数,且0到key的最大值之间,超过一半的key都有非空的值,那么wilddog客户端会将它们当作数组来处理。限制和约束描绘约束备注树的深度32key的长度768bytesU
9、TF-8编码,不能包含.$#/和ASCII控制字符0-31和127描绘约束备注一个叶子节点的数据大小1mbUTF-8编码通过SDK写入的数据大小2mbUTF-8编码限制通过REST写入数据大4mb小限制一次能读取的节点2000一次条件查询能返回的最500如使用limitToFirst()、limitToLast()等大条数保存数据的方式methoddescriptionset()写入和交换当前途径的数据update。修改部分子节点的数据push()在当前节点下新增一个数据,数据的key随机生成methoddescriptiontransaction。一个复杂数据被并发更新导致数据错误,使用事务
10、防止数据被并发更新用set()写数据set是Wilddog最根本的写数据操作。set()设置当前节点的值,假设当前节点已经存在值,set会将旧值交换成新值。为了理解set的工作原理,我们创立一个简单博客app,这个博客的app储存在这里:varref=newWilddog("s:<appId>.wilddogio/web/saving-data/wildblog");我们用唯一的用户名来标识一个用户,存储他们的全名和生日。首先,我们创立一个引用,然后用set储存数据,set可以传入string,number,boolean,object类型:varusersRe
11、f=ref.child("users");usersRef.set(alanisawesome:date_of_birth:"June23,1912",full_name:"AlanTuring",gracehop:date_of_birth:"December9,1906"full_name:"GraceHopper");这时,数据被嵌套保存到了相应的位置上,完成上面的过程,你也可以直接这样做usersRef.child("alanisawesome" ).set(date
12、ofbirth:"June 23, 1912"full name:"Alan Turing");usersRef.child("gracehop" ).set(dateofbirth:"December 9, 1906"full name:"Grace Hopper");这两种方式的区别是,假设/user下面原来有数据的时候,第一种方式会把数据全部覆盖掉,而第二种方式只会覆盖alanisawesome和gracehop两个子节点.更新已经存在的数据假设你想同时更新多个子节点,而不覆盖其他的子节点
13、,你可以使用update()函数:varhopperRef=usersRef.child("gracehop");hopperRef.update("nickname":"AmazingGrace");这样会更新Grace的数据,更新她的nickname。假设我们用set而不是update,date_of_birth和full_name都会被删除。保存一个列表当多个用户同时试图在一个节点下新增一个子节点的时候,这时,数据就会被重写,覆盖。为理解决这个问题,Wilddogpush()采用了生成唯一ID作为key的方式。通过这种方式,多个
14、用户同时在一个节点下面push数据,他们的key一定是不同的。这个key是通过一个基于时间戳和随机的算法生成的。wilddog采用了足够多的位数保证唯一性。用户可以用push向博客app中写新内容:varpostsRef=ref.child("posts");postsRef.push(author:"gracehop",title:"AnnouncingCOBOL,aNewProgrammingLanguage);postsRef.push(author:"alanisawesome",title:"TheTur
15、ingMachine");产生的数据有一个唯一ID:"posts":"-JRHTHaIs-jNPLXO":"author":"gracehop","title":"AnnouncingCOBOL,aNewProgrammingLanguage","-JRHTHaKuITFIhnj":"author":"alanisawesome","title":"TheTuringMachi
16、ne"获取口!一ID调用push会返回一个引用,这个引用指向新增数据所在的节点。你可以通过调用key()来获取这个唯一ID/通过push()来获得一个新的数据库地址varnewPostRef=postsRef.push(author:"gracehop",title:"AnnouncingCOBOL,aNewProgrammingLanguage");/获取push()生成的唯一IDvarpostID=newPostRef.key();使用事务保存数据当处理可能被并发更新导致损坏的复杂数据时,比方增量计数器,我们提供了事务操作。事务操作需要提供
17、两个参数:一个更新函数和一个可选的完成callback函数。更新函数提供当前数据,当前数据是云端读取的。举例说明,假设我们想在一个的博文上计算点赞的数量,我们可以这样写一个事务:varupvotesRef=newWilddog('s:<appId>.wilddogio/android/saving-data/wildblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');upvotesRef.transaction(function(current_value)/return(current_value|0)+1;);我们使用curren
18、tData.getValue!=null来判断计数器是否为空或者是自增加。假设上面的代码没有使用事务,当两个客户端在同时试图累加,那结果可能是为数字1且非数字2。注意:doTransaction()可能被屡次被调用,必须处理currentData变量为null的情况。当事务允许时,本地不会缓存从云端读取的数据。更多关于事务API的文档。到目前为止,我们已经理解到如何向Wilddog中保存数据,如今我们来看看如何查询数据。Wilddog查询数据的方式是绑定一个异步监听的回调函数,每当数据被第一次查询或者数据发生变化,这个回调函数都会被执行。重新看博客app的例子,我们可以这样读取博客数据:/获得
19、一个数据库连接实例varref=newWilddog("s:<appId>.wilddogio/web/saving-data/blog/posts");/监听数据ref.on("value",function(snapshot)console.log(snapshot.val();,function(errorObject)console.log("Thereadfailed:"+errorObject.code););运行这段代码,我们会看到控制台中打印出一个对象,包含所有的博客数据。每次当有新的博客数据被写入时,这个
20、回调函数都会被触发执行。回调函数接收一个Snapshot类型作为参数。一个Snapshot对象代表的是在指定的数据途径下,某一个时间点上数据的一个快照。调用它的val()函数,可以得到一个代表当前节点数据的javascript对象。假设途径节点下没有数据,那么这个Snapshot将为null。这个例子中我们用value,作为事件类型,用于读取当前途径节点下的所有数据。我们还可以使用另外三种数据事件类型。事件类型WildDog提供了四种数据事件:value,child_added,child_changed,child_removed。valuevalue事件用来读取当前节点的静态数据快照,va
21、lue事件在初次获取到数据时被触发一次,此后每当数据发生变化都会被触发。回调函数被执行时候,当前节点下所有数据的静态快照会被作为参数传入。child_added与value事件返回指定数据节点下的所有数据不同,child_added事件会为每一个现存的子节点数据触发一次,此后每当有子节点数据被增加时被触发一次。回调函数传入的也是DataSnapshot对象,包含的是新增子节点的数据。假设我们只想获取新增的博客数据,可以使用child_added事件:/获得一个数据库连接实例varref=newWilddog("s:<appId>.wilddogio/web/saving-
22、data/blog/posts");/获得新增加的数据ref.on("child_added",function(snapshot)varnewPost=snapshot.val();console.log("Author:"+newPost.author);console.log("Title:"+newPost.title););childchanged当子节点数据发生了改变时,childchanged事件会被触发,事件回调函数中传入的参数是子节点改变后的数据快照。我们可以使用child_changed事件来读取被修改的
23、博客数据:/获得一个数据库连接实例varref=newWilddog("s:/<appId>.wilddogio/web/saving-data/blog/posts");/获得发生改变的数据ref.on("child_changed",function(snapshot)varchangedPost=snapshot.val();console.log("Theupdatedposttitleis"+changedPost.title););childremoved当直接子节点被删除时,chiidremoved事件被触发
24、。事件回调函数中传入的参数是被删除的直接子节点的数据快照。在博客的例子中,我们可以使用child_removed事件,在有博客数据被删除时,在控制台中打印出来:/获得一个数据库连接实例varref=newWilddog("s:<appId>.wilddogio/web/saving-data/blog/posts");/获取被删除的数据ref.on("child_removed",function(snapshot)vardeletedPost=snapshot.val();console.log("Theblogposttitle
25、d'"+deletedPost.title+"'hasbeendeleted"););取消事件绑定通过off()函数可以取消一个事件回调函数的绑定:ref.off("value",originalCallback);一次性读取数据在某些场景下,也许需要事件的回调函数只被触发一次,然后立即取消。可以使用once()函数:ref.once("value",function(data)/执行业务处理,此回调函数只会被调用一次)查询数据Wilddog支持选择性的查询数据。要构造一个查询,需要先指定数据如何排序,可以使
26、用以下几个函数:orderByChild(),orderByKey(),orderByValue(),orderByPriority()。接下来,可以组合以下五个函数,构造出一个复杂的条件查询:limitToFirst(),limitToLast(),startAt(),endAt(),equalTo()。F面我们来举例如何进展数据查询。假设如今有一些关于恐龙的数据如下:"lambeosaurus":"height":,"length":,"weight":5000,"stegosaurus":
27、"height":4,"length":9,"weight":2500按照指定的子节点排序通过将子节点的途径名作为参数传递给orderByKey(),可以实现按指定子节点排序。例如,要按照height进展排序,可以:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByChild("height").on("child_added",function(snapshot)console.log(s
28、napshot.key()+"was"+snapshot.val().height+"meterstall"););不包含指定子节点的数据节点,将会按照该子节点为null进展排序,会排在最前边。每个查询都只能有一个排序。在一个查询中屡次调用orderByChild()会抛出错误。按照数据节点名称排序使用orderByKey()函数,可以实现按照数据节点的名称进展排序。下面的例子按照alpha字母顺序读取所有的恐龙数据:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");re
29、f.orderByKey().on("child_added",function(snapshot)console.log(snapshot.key(););按照数据节点的值排序使用orderByValue()函数,我们可以按照子节点的值进展排序。假设恐龙们进展了一场运动会,我们统计到它们的得分数据:"scores":"bruhathkayosaurus":55,"lambeosaurus":21,"linhenykus":80,"pterodactyl":93,"
30、stegosaurus":5,"triceratops":22要按照得分进展排序,我们可以构造一个这样的查询:varref=newWilddog("s:/<appId>.wilddogio/scores");scoresRef.orderByValue().on("value",function(snapshot)snapshot.forEach(function(data)console.log("The"+data.key()+"dinosaur'sscoreis&quo
31、t;+data.val();););按照优先级排序关于优先级,请参考API文档中的相关部分。复杂查询我们已经理解到数据排序的函数。接下来是limit类的和range类的查询,通过它们,可以构建出更为复杂的查询:limit查询limitToFirst()和limitToLast()两个函数用于设置最大多少个子节点数据会被同步。假设我们设置为100,那么初次获取到数据时,就只会最多触发100次事件回调函数。假设数据库中有少于100条消息数据,child_added事件将会为每一条消息数据被触发一次。假设消息数量多于100条,那么只有其中的100条会被触发child_added事件。假设我们使用了l
32、imitToFirst()函数,那么被触发的100条将会是排序最前边的100条。假设使用了limitToLast()函数,那么被触发的100条将是排序最后的100条。继续恐龙的例子,我们可以获得体重最大的两种恐龙:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByChild("weight").limitToLast(2).on("child_addedfunction(snapshot)console.log(snapshot.key(););我们为chil
33、d_added事件绑定的回调函数只会被执行2次。同理,我们可以使用limitToFirst()函数查询最矮的两种恐龙:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByChild("height").limitToFirst(2).on("child_added”,function(snapshot)console.log(snapshot.key(););我们也可以组合orderByValue()函数来使用limit类的查询。假设要构造出恐龙运动会得分的前3
34、名,我们可以构造这样一个查询:varref=newWilddog("s:<appId>.wilddogio/scores");scoresRef.orderByValue().limitToLast(3).on("value",function(snapshot)snapshot.forEach(function(data)console.log("The"+data.key()+"dinosaur'sscoreis"+data.val();););range查询使用startAt(),endA
35、t(),和equalTo()函数,我们可以任意指定任意值的范围进展查询。例如,假设要查询所有至少3米高以上的恐龙,可以组合orderByChild()和startAt()查询:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByChild("height").startAt(3).on("child_added",function(snapshot)console.log(snapshot.key();我们可以使用endAt()来查询按照字母排序,所有
36、名字排在Pterodactyl之前的恐龙:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByKey().endAt("pterodactyl").on("child_added",function(snapshot)console.log(snapshot.key(););注意,startAt()和endAt()都是包含边界值的,也就是说“pterodactyl'符合上边的查询条件。我们可以同时使用startAt()和endAt()来限定一个
37、范围。下面的例子查询出所有名字以字母“6开头的恐龙:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByKey().startAt("b").endAt("b").on("child_added",function(snapshot)console.log(snapshot.key(););这个例子中使用的“下符号是ASCII中的126字符。因为它排在所有常规的ASCII字符之后,所以这个查询匹配所有以b开头的值。使用equalTo
38、()函数,可以进展精准的查询。例如,查询所有的25米高的恐龙:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.orderByChild("height").equalTo(25).on("child_added",function(snapshot)console.log(snapshot.key(););同样的,startAt(),endAt()函数也可以和orderByValue()函数组合进展range查询。总结组合这些函数,我们可以构造出各种复杂的查询。
39、例如,要找出长度小于Stegosaurus但最接近的恐龙的名字:varref=newWilddog("s:<appId>.wilddogio/dinosaurs");ref.child("stegosaurus").child("height").on("value",function(stegosaurusHeightSnapshot)varfavoriteDinoHeight=stegosaurusHeightSnapshot.val();varqueryRef=ref.orderByChild(&
40、quot;height").endAt(favoriteDinoHeight).limitToLast(2)queryRef.on("value",function(querySnapshot)if(querySnapshot.numChildren()=2)/数据是按照height字段的值升序排列的,所以我们需要获得第一个元素。querySnapshot.forEach(function(dinoSnapshot)console.log("Thedinosaurjustshorterthanthestegasaurusis"+dinoSnap
41、shot.key();/返回true意味着我们只需要循环forEach()一次returntrue;);elseconsole.log("Thestegosaurusistheshortestdino");););数据排序本小节介绍在使用各种排序方式时,数据终究是如何排序的。orderByChild当使用orderByChild(key)时,按照子节点的公有属性key的value进展排序。仅当value为单一的数据类型时,排序有意义。假设key属性有多种数据类型时,排序不固定,此时不建议使用orderByChild(key)获取全量数据,例如,"scores&qu
42、ot;:"no1":"name":"tyrannosaurus","score":"120","no2":"name":"bruhathkayosaurus","score":55,"no3":"name":"lambeosaurus”"score":21,"no4":"name":"linheny
43、kus”"score":80,"no5":"name":"pterodactyl""score":93,"no6":"name":"stegosaurus""score":5,"no7":"name":"triceratops""score":22,"no8":"name":"bronto
44、saurus""score":true霸王龙的分数是string类型,雷龙的分数是boolean类型,而其他恐龙的分数是numberic类型,此时使用orderByChild(key)获得全量数据时,是一个看似固定的排序结果;但是配合使用limitToFirst()时,将获得不确定的结果。Object类型数据的value值为null,不会出如今结果中。当配合使用startAt()、endAt()和equalTo()时,假设子节点的公有属性key包含多种数据类型,将按照这些函数的参数的类型排序,即只能返回这个类型的有序数据。上面的数据假设使用orderByChild
45、('score').startAt(60).limitToFirst(4)将得到下面的结果:"no4":"name":"linhenykus""score":80,"no5":"name":"pterodactyl"score":93注意:假设path与value的总长度超过1000字节时,使用orderByChild(key)将搜索不到该数据。orderByKey当使用orderByKey()对数据进展排序时,数据将会按照下面的
46、规那么,以字段名升序排列返回。注意,节点名只能是字符串类型。1,节点名能转换为32-bit整数的子节点优先,按数值型升序排列。2,接下来是字符串类型的节点名,按字典序排列。orderByValue当使用orderByValue()时,按照直接子节点的value进展排序。仅当value为单一的数据类型时,排序有意义。假设子节点包含多种数据类型时,排序不固定,此时不建议使用orderByValue()获取全量数据,例如,"scores":"tyrannosaurus":"120","bruhathkayosaurus"
47、:55,"lambeosaurus":21,"linhenykus":80,"pterodactyl":93,"stegosaurus”:5,"triceratops":22,"brontosaurus":true霸王龙的分数是string类型,雷龙的分数是boolean类型,而其他恐龙的分数是numberic类型,此时使用orderByValue()获得全量数据时,是一个看似固定的排序结果;但是配合使用limitToFirst()时,将获得不确定的结果。Object类型数据的valu
48、e值为null,不会出如今结果中。当配合使用startAt()、endAt()和equalTo()时,假设子节点的value包含多种数据类型,将按照这些函数的参数的类型排序,即只能返回这个类型的有序数据。上面的数据假设使用orderByValue().startAt(60).limitToFirst(4)将得到下面的结果:"linhenykus":80,"pterodactyl":93注意:假设path与value的总长度超过1000字节时,使用orderByValue()将搜索不到该数据。orderByPriority当使用orderByPriorit
49、y()对数据进展排序时,子节点数据将按照优先级和字段名进展排序。注意,优先级的值只能是数值型或字符串。1,没有优先级的数据默认优先。2,接下来是优先级为数值型的子节点。它们按照优先级数值排序,由小到大。3,接下来是优先级为字符串的子节点。它们按照优先级的字典序排列。4,当多个子节点拥有一样的优先级时包括没有优先级的情况,它们按照节点名排序。节点名可以转换为数值类型的子节点优先数值排序,接下来是剩余的子节点字典序排列。构造恰当的NoSQL存储构造需要事先考虑很多因素。最重要的是,必需要知道将来数据会被如何查询,如何存储数据才能使查询最方便。防止层级过深尽管可以使用JSON任意地组织数据,但不同的
50、组织方式对读取T能的影响是很大的。Wilddog的工作方式是当你查询某个节点,Wilddog会返回这个节点下的所有子节点。所以,应该尽可能使数据扁平化,就像组织SQL关系型数据表一样。我们不推荐这种理论/一个非常差的充满嵌套的数据构造。请勿模拟。/对"rooms"进展遍历查找来获得名字需要下载很多很多的messages。"rooms":"one":"name":"roomalpha","type":"private","messages"
51、;:"m1":"sender":"mchen","message":"foo","m2":.,/非常长的messages列表对于这种嵌套存储的设计,很难遍历所有的数据。比方列出所有的rooms这样一个很简单的操作,也会查t整个rooms数据节点,返回所有的rooms下的数据节点到客户端。使数据扁平化假设数据分布到不同的途径下,那么就可以根据需要查询最小化的数据量,大大进步查询性能:“rooms数据节点下仅包含房间的根本信息和唯一ID。"rooms":&qu
52、ot;one":"name":"roomalpha","type":"private","two":.,"three":.,/room成员可以很方便的的存取"members":"one":"mchen":true,"hmadi":true,"two":.,"three":.,/消息数据与其他数据别分开,这样我们在查询其他数据时就不收消息数据的影响,
53、从而提升性能。/消息数据可以通过roomID方便的分页和查询。"messages":"one":"ml":"sender":"mchen","message":"foo","m2":.,"m3":.,"two":.,"three":.这样组织数据,就可以很方便的查询room列表了,只需要传输很少的字节数。message数据也可以很容易的查询。使数据可扩展很多时候需要查询一个列表
54、的一个子集数据,尤其是当这个列表中包含多达数千条或更多记录时。当这个数据之间的关系是单向且数据比较稳定的时候,我们可以简单的把子节点数据嵌套到父节点之下:"users":"john":"todoList":"rec1":"Walkthedog","rec2":"Buymilk","rec3":"WinagoldmedalintheOlympics但很多时候数据频发变化,或者有时候必须把数据拆分存储到不同的途径下John可能有一
55、个长达数千项的todo列表。通常可以用获取数据中介绍的函数来查询一个列表的子集。但仅仅如此可能还是不够的。考虑一个例子,users和groups之间的双向关系。user可以属于group,group包含一个user列表。乍看之下数据可能这样组织:"users": "mchen": "name":"brinchen": "name":"hmadi": "name":"Mary Chen" ,"Byambyn Rinchen&qu
56、ot; ,"Hamadi Madi" ,"groups":"alpha":"name":"AlphaTango"members":"m1":"mchen","m2":"brinchen""m3":"hamadi","bravo":.,"charlie":.看起来不错。但是当需要判断一个user属于哪些group的时候,困难就来了
57、。我们可以在数据发生改变的时候遍历并更新所有的group,但这样做本钱很高,也很慢。更糟糕的是,假设Mary没有权限查看所有的group时怎么办呢?当查询整个列表时,会得到一个没有权限访问的错误。我们需要的是一种优雅的方式,可以列出Mary属于哪些group,只需要查询这些group就行了。数据可以这样组织:"users":"mchen":"name":"MaryChen",/在Mary的数据下,建立他所属group的索引。"groups":/这里的值是什么并不重要。重要的是这个子节点的key存
58、在。"alpha":true,"charlie":true,.,"groups":.我们把关系数据同时存储在了Mary的记录下和group数据下,这样造成了数据的重复。假设要把Mary从一个组中删除,就需要更新两个地方。对于双向的关系来说,这样的冗余是有必要的。这样做使我们可以很高效的查询Mary的个人信息,即使users和groups都有百万级的数据,且规那么表达式制止访问不相关的数据时。为什么我们把id作为key,而把value设置为true呢?这样做是有好处的。这样使得检查一个id是否存在变得非常简单,只需要读取/users/m
59、chen/groups/$group_id,看它是否为null就可以了。/判断Mary是否属于alphagroupvarref=newWilddog("s:<appId>.wilddogio/web/org/users/mchen/groups/alpha");ref.once('value',function(snap)varresult=snap.val()=null?'isnot':'is'console.log('Mary'+result+'amemberofalphagroup);
60、);平安是一个非常重大的话题,通常也是app开发中最困难的部分之一。Wilddog使用一种声明式的规那么表达式,对数据的访问权限进展配置,让这一切变得简单。认证用户ID是一个非常重要概念,不同的用户拥有不同的数据和不同的权限,比方,在一个聊天程序中,每一条消息都有它的发布者,用户可以删除自己的消息,而不能删除别人的。平安的第一步是用户认证。Wilddog提供了以下终端用户认证的方式:?集成微博,微信,QQ等社交平台的OAuth认证?Email/密码登录,并且提供用户管理?匿名用户访问?自定义token,方便用户集成已有的用户账户系统。授权知道用户的身份只是平安的一部分,一旦你知道谁在访问数据,
61、你需要一种方式来控制访问权限。Wilddog提供了一种声明式的表达式语言,你可以在控制面板中的规那么表达式''tab下进展编辑这些规那么表达式让你可以管理数据的访问规那么。规那么级联应用到其子节点。"rules":"foo":".read":true,".write":false这个例子允许所有人访问数据节点fooo规那么表达式包含一系列内置对象和函数。最重要的一个内置对象是auth,它在终端用户认证的时候生成,包含终端用户的信息和用户的唯一id:auth.uid。auth对象是很多规那么表达式的根
62、底。"rules":"users":"$user_id":".write":"$user_id=auth.uid"这个规那么保证了:只有终端用户的唯一id等于动态途径$user_id的值时,用户才能写入数据数据校验规那么表达式中还包含一个.validate规那么,用于对数据进展校验,确保数据的格式正确。它的语法和.read与.write一样,不同的是.validate规那么不会向下级联。"rules":"foo":".validate"
63、:"newData.isString()&&newData.val().length()<100"这一规那么确保了在/foo/节点下,写入的数据必须是字符串类型,且必须长度小于100。.validate规那么可以使用的内置对象和函数与.read和.write一样。"rules":"user":".validate":"auth!=null&&newData.val()=auth.uid"这一规那么弓S迫使写入/user/下的数据必须是当前登陆用户的唯一id。.validate规那么并不是要彻底取消应用中的数据校验代码。为了获得更好的性能和用户体验,你仍然必须在应用代码中对数据进展校验。理解更多到此为止,你应该对Wilddog中的应用平安机制有了一个大体的理解。规那么表达式是复杂且强大的,本开发向导中只涵盖了非常小的一部分。更多关于规那么表达式的细节,请参考规那么表达式文档,这里将会讲述所有的内置函数和对象。绝大多数应用都需要一套终端用户账号体系。对终端用户进展唯一标识之后,才能对用户进展个性化的用户体验,控制用户对数据的访
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 十借款合同范例
- 房屋全款协议合同范例
- 天津滨海汽车工程职业学院《水墨艺术》2023-2024学年第一学期期末试卷
- 卡车维修合同范例
- 双方自愿离婚合同范例
- 消防隐患租房合同范例
- 档案仿真合同范例
- 医学心理伦理学测试题(附答案)
- 辐射安全考核核医学模考试题+答案
- 公司货款欠款合同范例
- 现代药物制剂与新药研发智慧树知到答案章节测试2023年苏州大学
- 肺结核的学习课件
- 心肺复苏术最新版
- 2023-2024学年贵州省贵阳市小学数学六年级上册期末自测提分卷
- GB/T 9115.2-2000凹凸面对焊钢制管法兰
- 永久避难硐室安装施工组织措施
- 元旦节前安全教育培训-教学课件
- 芯片工艺流程课件1
- 化工原理设计-苯-氯苯分离过程板式精馏塔设计
- 新教材人教A版高中数学选择性必修第一册全册教学课件
- IEC60335-1-2020中文版-家用和类似用途电器的安全第1部分:通用要求(中文翻译稿)
评论
0/150
提交评论