ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Lovefield 与 AngularJS 实战:构建奥运奖牌数据查询 Demo(olympia_db 详解)

Lovefield 与 AngularJS 实战:构建奥运奖牌数据查询 Demo(olympia_db 详解) 关系型数据库数据库前端【免费下载链接】lovefieldLovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.项目地址https://gitcode.com/gh_mirrors/lov/lovefield点击查看免费下载Lovefield 是一个用 JavaScript 编写、跨浏览器运行的 Web 应用关系型数据库提供类似 SQL 的快速、安全、易用的查询 API。本指南以仓库中 demos/olympia_db/angular 目录下的官方 Demo 为核心完整讲解如何将 Lovefield 集成进 AngularJS 应用从环境搭建、数据库 Schema 定义、JSON 数据导入到动态查询构建与结果可视化。读完本文你将掌握一套可直接复用的「Lovefield AngularJS」前端数据库落地模式。一、Demo 概览用 Lovefield 查询百年奥运奖牌数据该 Demo 名为olympia-db核心场景是将一份包含 1896 年以来历届奥运会奖牌得主记录的 JSON 数据约 37.9 万行记录见 demos/olympia_db/data/olympic_medalists.json加载进 Lovefield 内存数据库然后通过下拉表单组合筛选条件年份范围、举办城市、项目、国家、奖牌颜色、性别等实时生成并执行查询最后以表格形式展示结果。页面同时提供一个只读文本框实时显示由query.toSql()生成的等效 SQL 语句方便开发者在调试时直观理解 Lovefield 查询构建器的行为——这是理解 Lovefield 谓词Predicate与查询构造 API 的最佳教学入口。二、环境搭建六步跑起 Demo官方 demos/olympia_db/angular/README.md 给出了完整的六步安装流程步骤命令说明Step 1npm install -g gulp全局安装 Gulp如已安装可跳过用于启动本地 Web 服务器Step 2npm install -g bower全局安装 Bower用于拉取前端依赖Step 3npm install .依据 package.json 安装 Gulp 插件等开发依赖Step 4bower install依据 bower.json 安装 AngularJS、jQuery、Bootstrap、Bootstrap Table 及 Lovefield 本体Step 5gulp debug启动本地开发服务器默认端口 8000访问前会自动完成依赖与数据的拷贝Step 6打开http://localhost:8000/demo.html开始组合条件并执行查询依赖清单package.json 声明了构建期依赖gulp^3.9.0任务编排gulp-webserver^0.9.1本地静态服务器支持 livereloadfs-extra^0.24.0文件拷贝nopt^3.0.4命令行参数解析用于自定义端口。bower.json 声明了运行时依赖angular^1.5.5MVVM 框架负责视图绑定与控制器bootstrap^3.3.5 与bootstrap-table^1.8.1结果表格的分页渲染jquery^3.5.0Bootstrap Table 的底层依赖lovefield#master从 master 分支安装 Lovefield 库本体。gulp debug 背后的自动化执行gulp debug时gulpfile.js 会先串行执行两个准备任务copy_dependencies将bower_components中的angular.min.js、bootstrap*.js/css、bootstrap-table*.js/css、jquery.min.js以及lovefield/dist/lovefield.min.js统一拷贝到本地lib目录copy_data把仓库共享数据 demos/olympia_db/data/olympic_medalists.json 与 demos/olympia_db/data/column_domains.json 拷贝到 Demo 自己的data目录。随后通过gulp-webserver在指定端口--portnumber可自定义默认 8000提供服务并开启livereload与directoryListing方便调试。另有gulp clean清理lib、data临时目录gulp export将整个 Demo 连同依赖导出到dist目录以便部署。三、页面结构查询面板 结果表格的 AngularJS 布局入口页面 demo.html 是一个典型的 AngularJS 单页body ng-appmyApp div idquery-builder ng-controllerQueryBuilderController as queryBuilder !-- 8 个下拉筛选器From year / To year / Hosting city / Discipline / Event / Country / Color / Gender -- button ng-clickqueryBuilder.clear()Clear/button button ng-clickqueryBuilder.search()Search/button textarea ng-modelsqlQuery readonly/textarea /div div idresults ng-controllerResultsController as resultsController h1Found {{resultsController.getResults().length}} results./h1 table idresults-table/table /div script srcdemo.js/script /body页面顶部按顺序引入angular.min.js、jquery.min.js、bootstrap.min.js、bootstrap-table.min.js和lovefield.min.js均来自lib目录再引入demo.css。视图层只负责展示业务逻辑全部收敛在两个控制器中QueryBuilderController维护筛选值、构建并执行查询、展示 SQLResultsController把查询结果交给结果表格渲染。应用装配代码位于 demo.js 末尾的main()function main() { var app angular.module(myApp, []); app.service(DbService, DbService); // 数据库服务建表、连接、导数据 app.service(ResultsService, ResultsService); // 结果共享服务 app.controller(ResultsController, [ResultsService, ResultsController]); app.controller(QueryBuilderController, [$scope, $http, DbService, ResultsService, QueryBuilderController]); } main();注意这里通过服务Service注入而非全局变量来共享数据库实例与查询结果两个控制器互不直接依赖体现了 AngularJS 依赖注入与职责分离的典型用法。四、核心数据层DbService 的模式定义、连接与数据导入DbServicedemo.js封装了数据库的全部生命周期是理解 Lovefield 编程模型的关键。4.1 定义 SchemaDbService.prototype.buildSchema_ function() { var schemaBuilder lf.schema.create(olympia, 1); schemaBuilder.createTable(Medal). addColumn(city, lf.Type.STRING). addColumn(color, lf.Type.STRING). addColumn(country, lf.Type.STRING). addColumn(discipline, lf.Type.STRING). addColumn(eventGender, lf.Type.STRING). addColumn(event, lf.Type.STRING). addColumn(firstName, lf.Type.STRING). addColumn(gender, lf.Type.STRING). addColumn(lastName, lf.Type.STRING). addColumn(sport, lf.Type.STRING). addColumn(year, lf.Type.NUMBER). addNullable([firstName]). addIndex(idx_year, [year]). addIndex(idx_lastName, [lastName]); return schemaBuilder; };要点解析lf.schema.create(olympia, 1)创建名为olympia、版本号为1的数据库。版本号是 Lovefield 升级与迁移机制的锚点通过链式调用createTable(Medal)建表并逐一声明列名与类型10 个lf.Type.STRING文本列城市、奖牌颜色、国家、项目、赛事、性别、姓名、运动等 1 个lf.Type.NUMBER数值列year注意奖牌记录中的年份存为数值以便范围比较addNullable([firstName])声明firstName列允许为空——早期奥运记录确实存在姓名缺失Schema 层就保证了数据兼容性addIndex(idx_year, [year])与addIndex(idx_lastName, [lastName])为最常用的查询列建立索引。Lovefield 的查询引擎会利用这些索引做范围扫描与排序优化对应 lib/proc/index_range_scan_pass.js 等重写流程这也正是 Demo 中按年份区间、按姓名过滤查询高效的原因。4.2 连接数据库并按需导数据init_()是完整的初始化链DbService.prototype.init_ function() { return this.buildSchema_().connect().then(( function(database) { this.db database; window.db database; // 挂到 window便于控制台调试 return this.checkForExistingData_(); }).bind(this)).then(( function(dataExist) { return dataExist ? Promise.resolve() : this.insertData_(); }).bind(this)); };流程分三步连接buildSchema_().connect()返回一个 Promise解析为lf.Database实例。Lovefield 支持多种底层存储IndexedDB、WebSQL、内存等Demo 未显式指定存储类型在支持 IndexedDB 的浏览器中默认落盘到 IndexedDB——因此刷新页面后数据仍在这正是checkForExistingData_存在的意义幂等检查checkForExistingData_执行db.select().from(medal).exec()通过返回行数是否大于 0 判断数据库是否已初始化过避免重复导入 37.9 万条记录造成性能浪费条件导入仅当数据库为空时才调用insertData_。insertData_演示了 Lovefield 的批量写入范式DbService.prototype.insertData_ function() { var medal this.db.getSchema().table(Medal); return this.http_.get(../data/olympic_medalists.json).then( function(response) { var rows response.data.map(function(obj) { return medal.createRow(obj); }); return this.db.insert().into(medal).values(rows).exec(); }); };先用$http拉取 JSON再把每条普通对象通过medal.createRow(obj)包装成 Lovefield 行对象字段名与 Schema 列名一一对应见 olympic_medalists.json 中的city/year/sport/discipline/country/gender/event/color/lastName/firstName等字段最后db.insert().into(medal).values(rows).exec()一次性批量插入。整条链路全部基于 Promise与 AngularJS 生态自然衔接。get()方法返回缓存的初始化 PromisewhenInitialized_后续所有查询都先等待数据库就绪这是多控制器并发访问数据库时的安全模式。五、查询构建谓词组合与动态 SQLQueryBuilderControllerdemo.js是查询逻辑的核心。5.1 填充下拉选项populateUi_()通过$http拉取 column_domains.json将其中的cities、years、disciplines、countries、genders、colors、events等去重域值注入控制器属性再经ng-repeat渲染成下拉选项。这样既避免让用户面对 37.9 万行的原始数据也让查询条件始终是合法取值。5.2 把界面状态翻译成谓词getPredicates_()将界面上的 8 个筛选值翻译为 Lovefield 谓词if (this.scope_.countrySelection ! this.unboundValue) { predicates.push(medal.country.eq(this.scope_.countrySelection)); } // ... 其余列同理使用 eq if (this.scope_.fromYearSelection ! this.unboundValue this.scope_.toYearSelection ! this.unboundValue) { var minYear Math.min(this.scope_.fromYearSelection, this.scope_.toYearSelection); var maxYear Math.max(this.scope_.fromYearSelection, this.scope_.toYearSelection); predicates.push(medal.year.between(minYear, maxYear)); } else if (this.scope_.fromYearSelection ! this.unboundValue) { predicates.push(medal.year.gte(this.scope_.fromYearSelection)); } else if (this.scope_.toYearSelection ! this.unboundValue) { predicates.push(medal.year.lte(this.scope_.toYearSelection)); } return predicates.length 0 ? lf.op.and.apply(null, predicates) : null;值得注意的工程细节每个下拉初始值为unboundValueundefined用!判断是否被用户选择未选择的列不参与过滤实现「条件越多查询越精确」的可叠加筛选年份区间用Math.min/Math.max归一化用户即使把 From/To 选反了也能得到正确闭区间只选一端时退化为gte或lte单边过滤多个谓词通过lf.op.and.apply(null, predicates)合并为 AND 组合谓词对应 lib/pred/combined_predicate.js 的实现当没有任何条件时返回null直接退化为全表select().from(medal)保证「无筛选也能查询」。5.3 执行查询并展示 SQLsearch()是完整链路QueryBuilderController.prototype.search function() { this.buildQuery_().then(function(query) { this.scope_.sqlQuery query.toSql(); // 生成等效 SQL 并回显到页面 return query.exec(); }.bind(this)).then(function(results) { this.resultsService_.setResults(results); // 交给结果表格 }.bind(this)); };buildQuery_()内部在数据库就绪后根据谓词是否存在选择db.select().from(medal).where(predicates)或db.select().from(medal)。query.toSql()实现于 lib/query/to_sql.js把 Lovefield 查询对象翻译成人类可读的 SQL 字符串回填到页面的sqlQuery文本框让使用者即时看到自己的操作产生了怎样的SELECT ... WHERE ...语句。六、结果展示Bootstrap Table 渲染查询结果ResultsServicedemo.js负责把查询结果交给 Bootstrap TableResultsService.prototype.setResults function(results) { this.results_ results; var headerData results.length 0 ? Object.keys(results[0]).map(function(columnName) { var columnOptions {field: columnName, title: columnName}; if (columnName color) { columnOptions.cellStyle function(value) { return {classes: [value.toLowerCase()]}; }; } return columnOptions; }) : []; $(#results-table).bootstrapTable(destroy); $(#results-table).bootstrapTable({ columns: headerData, data: results, pageSize: 25, pagination: true, paginationVAlign: top, sortable: false }); };技巧点列定义动态生成以第一条结果的字段名作为表头查询结果结构变化时表格自适应无需硬编码列color列附加cellStyle把Gold/Silver/Bronze映射为 CSS 类名配合demo.css即可给奖牌着色开启pagination且每页 25 条缓解大结果集例如只筛选「金牌」的渲染压力。页面顶部的Found N results.由 ResultsController 实时反映结果条数配合 Clear 按钮一键重置所有筛选条件与结果。七、从 Demo 到实战可借鉴的集成模式综合整个 Demo可以提炼出 Lovefield 与 AngularJS乃至任意前端框架集成的通用四步模式服务化封装把「建 Schema → 连接 → 幂等导数据 → 暴露查询入口」封装为独立服务如 DbService通过 DI 注入而非全局变量访问保证单例与生命周期可控数据导入幂等化先select().from(table).exec()探测是否已有数据再决定是否执行大批量insert()避免重复初始化动态谓词组装界面筛选状态 → 一组eq/between/gte/lte谓词 →lf.op.and合并无谓词时安全退化为全表查询查询可观测利用query.toSql()将内部查询翻译为 SQL 回显对调试与教学都极有价值。该 Demo 的 Polymer 变体demos/olympia_db/polymer使用同一份数据集与 Schema 展示了另一种框架集成方式可对照阅读以体会 Lovefield「存储与查询引擎独立于 UI 框架」的跨框架特性。八、延伸阅读官方文档总览docs/spec_index.md 与 docs/dd_index.md分别覆盖 API 规范与设计文档Schema 与数据类型docs/spec/01_schema.md查询语义与构建器docs/spec/04_query.md事务模型docs/spec/05_transaction.md查询计划与索引优化源码lib/proc、lib/index其余官方 Demodemos/moviedb、demos/todo、demos/scrum 展示了在不同框架与场景下的 Lovefield 用法。赞分享关系型数据库数据库前端【免费下载链接】lovefieldLovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.项目地址https://gitcode.com/gh_mirrors/lov/lovefield点击查看免费下载相关推荐Lovefield 与 Polymer 集成实战奥林匹克奖牌数据库 Demo 从搭建到查询Lovefield 与 Polymer 集成实战奥林匹克奖牌数据库 Demo 从搭建到查询 本篇技术指南以仓库内 demos/olympia_db/polym关系型数据库数据库前端Lovefield 电影数据库 Demo 实战表连接、参数化查询、Observer 与原生 IndexedDB 对比Lovefield 电影数据库 Demo 实战表连接、参数化查询、Observer 与原生 IndexedDB 对比 本指南基于 demos/moviedb关系型数据库数据库前端Lovefield 查询系统详解从 SQL Builder 到参数化查询与数据观察的完整实践指南Lovefield 查询系统详解从 SQL Builder 到参数化查询与数据观察的完整实践指南 导读 本文围绕 Lovefield 官方规范文档 docs/关系型数据库数据库前端上一篇如何快速掌握FastAPI面向全栈开发者的高性能Python框架终极指南下一篇TypeDB部署指南从本地开发到生产环境的完整配置创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表