日常在电商小程序中,常见的功能是搜索。搜索一般是指输入关键词,在多个字段中进行模糊匹配,如匹配标题、正文等。如果我们自己想实现一下搜索功能,该如何做呢?
1 数据源的设计
搜索一般是从数据源中检索数据,为此我们需要设计一个商品的数据源,字段如下:
2 数据录入
数据源设计好之后,我们需要录入一些测试数据,方便我们开发功能。登录控制台,点击管理数据,打开后台,录入对应的数据
3 后端开发
要想实现搜索功能,我们先需要开发后端功能。低代码中后端功能的开发是在自定义连接器中完成。点击自定义连接器,点击新建自定义连接器
输入名称和标识
点击添加方法,输入方法的名称和标识,意图选择查询列表,类型选择自定义代码
代码框架的话我们沿用我们在以前分享的分页方法,需要将数据源替换成商品数据源
module.exports = async function (params, context) { const result = await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview').skip(params.pageSize*(params.pageNo-1)).limit(params.pageSize).get(); const total = await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview').count(); // 在这里返回这个方法的结果,需要与出参定义的结构映射 return { pageNo:params.pageNo, pageSize:params.pageSize, total:total.total, records: result.data }; };
有了代码模板之后我们需要考虑我们的需求是什么,要如何实现。需求是按照关键字去标题和简介里模糊匹配。实现的话我们先考虑一下如果用关系型数据库如何实现。
select * from product p where p.title like '%生煎包%' or p.desc like '%生煎包%'
多条件在关系型数据库用or表达,如果是模糊匹配是用like关键词,%号表示去字段里模糊匹配数据
低代码是使用的文档型数据库,文档型数据库的特点是所有的语法都要用对象的形式进行组装,查询条件是用where,我们可以看看官方文档where如何使用
我们也可以一次性获取多条记录。通过调用集合上的 where 方法可以指定查询条件,再调用 get 方法即可只返回满足指定查询条件的记录
where 方法接收一个对象参数,该对象中每个字段和它的值构成一个需满足的匹配条件,各个字段间的关系是 “与” 的关系,即需同时满足这些匹配条件
显然不满足我们的需求,因为他是要求同时满足才可以,那where支不支持或的关系呢?答案是肯定的,如果需要支持或的关系,需要用到查询指令
假设我们需要查询进度大于 30% 的待办事项,那么传入对象表示全等匹配的方式就无法满足了,这时就需要用到查询指令。数据库 API 提供了大于、小于等多种查询指令,这些指令都暴露在 db.command 对象上
或调用需要用到逻辑指令,这里用到了or,官方给出的例子是这样的、
const cloudbase = require("@cloudbase/js-sdk"); const app = cloudbase.init({ env: "xxxx" }); // 1. 获取数据库引用 var db = app.database(); const _ = db.command; db.collection("todos") .where( _.or([ { progress: _.lte(50) }, { style: { color: _.in(["white", "yellow"]) } } ]) ) .get() .then((res) => { console.log(res.data); });
要使用指令,需要先进行定义,这句话表示获取指令的意思
const _ = db.command;
调用指令的时候是用_.的语法,日常编程中经常会少写一个点导致代码报错。如果需要多个条件,需要传入一个数组。数组的每个元素是对象,左边是字段标识,右边是传入的值。值的话我们可以从自定义的连接器的入参获取,获取的时候用params对象然后使用点的语法调用入参即可
多字段的问题解决后,需要考虑的是模糊匹配该如何实现。文档型数据库模糊匹配是使用的正则表达式,文档中给出的正则使用示例是:
db.collection('todos').where({ description: /miniprogram/i }) // 数据库正则对象 db.collection('todos').where({ description: db.RegExp({ regexp: 'miniprogram', options: 'i', }) }) // 用 new 构造也是可以的 db.collection('todos').where({ description: new db.RegExp({ regexp: 'miniprogram', options: 'i', }) })
多条件和模糊匹配都梳理清楚后,我们最终的代码是
module.exports = async function (params, context) { const db = context.database const _ = db.command const result = await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview'). skip(params.pageSize*(params.pageNo-1)).limit(params.pageSize) .where(_.or([ {name:db.RegExp({ regexp: params.keyword, options: 'i', })}, {desc:db.RegExp({ regexp: params.keyword, options: 'i'})} ])) .get(); const total = await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview').where(_.or([ {name:db.RegExp({ regexp: params.keyword, options: 'i', })}, {desc:db.RegExp({ regexp: params.keyword, options: 'i'})} ])).count(); // 在这里返回这个方法的结果,需要与出参定义的结构映射 return { pageNo:params.pageNo, pageSize:params.pageSize, total:total.total, records: result.data }; };
如果想测试的话,先需要填写入参,入参可以参考我的
出参的话,在方法测试成功直接点击出参映射按钮就可以
4 前端开发
低码有个好处是,如果后端写好之后,我们前端只需要进行配置,无需编写前端代码,这样也方便了不少。搜索功能的话我们用两个组件就可以实现,在页面中添加单行输入组件和数据列表组件
组件放入之后,要考虑在单行输入组件输入的内容如何传入后台,为此我们需要在变量里定义一个变量接收输入
给单行输入组件设置一个事件,当单行输入组件中值改变是就赋值给定义好的变量
选择数据列表组件,我们选择自定义连接器里的模糊匹配方法,并设置好参数。这里的keyword我们从变量绑定即可
预览的时候发现一个问题,输入关键词无法查出数据来,提示regexp must be a string
看来是关键词不允许为空,根据需求,我们关键词啥都不输入时需要查询全部数据。那我们改一下自定义连接器,增加一个查询条件是否为空的判断,如果为空我们就查全部,不为空我们就做模糊匹配
module.exports = async function (params, context) { const db = context.database const _ = db.command let result = {data:[]} let total = 0 if(params.keyword ==""){ result =await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview'). skip(params.pageSize*(params.pageNo-1)).limit(params.pageSize) .get(); total = await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview').count(); }else{ result =await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview'). skip(params.pageSize*(params.pageNo-1)).limit(params.pageSize) .where(_.or([ {name:db.RegExp({ regexp: params.keyword, options: 'i', })}, {desc:db.RegExp({ regexp: params.keyword, options: 'i'})} ])) .get(); total = await context.database.collection('lcap-data-26caupXt1-product_vfxwrnn-preview').where(_.or([ {name:db.RegExp({ regexp: params.keyword, options: 'i', })}, {desc:db.RegExp({ regexp: params.keyword, options: 'i'})} ])).count(); // 在这里返回这个方法的结果,需要与出参定义的结构映射 } return { pageNo:params.pageNo, pageSize:params.pageSize, total:total.total, records: result.data }; };
测试发现,输入值的时候,不能自动触发列表视图的刷新,看来自定义连接器还不能做到那么智能。如果是这样的话,我们只能通过普通容器来自己实现数据绑定了,如果希望还是使用数据列表组件还需要继续等待官方能力的更新才行。
总结
我们本篇利用自定义连接器实现了关键字的模糊匹配功能,总体上还是需要熟悉云开发和微搭低代码的相关知识才可以顺利开发出功能来。涉及到业务逻辑的部分免不了要写前端或者后端的代码,总体上写代码还是更灵活一些,如果用无代码的配置方案就要求官方能力足够好才可以。