对象
安装使用
npm install leancloud-storage --save
# debug模式
DEBUG=leancloud* node src/leancloud.js
初始化
const AV = require("leancloud-storage");
const { Query, User, Object } = AV;
AV.init({
appId: "Xxx",
appKey: "2233",
serverURL: "https://plqzch1l.lc-cn-n1-shared.com",
});
新增
// extend 一个Class 相当于一张表
const Config = Object.extend("Config");
const config = new Config();
// 等价于
const config = new Object("Config");
config.set("title", "快递详情");
config.set("key", "book_length");
config.set("value", "11");
config.save().then((res) => {
console.log(res);
});
查询
const query = new Query("Config");
query.get("620e6d13b2ace54e35218427").then((row) => {
const key = row.get("key");
const value = row.get("value");
const title = row.get("title");
console.log(title, key, value);
});
修改
// 更新对象
const todo = AV.Object.createWithoutData("Todo", "582570f38ac247004f39c24b");
todo.set("content", "这周周会改到周三下午三点。");
todo.save();
// 查看哪些属性有尚未保存的修改
todo.dirtyKeys(); // ['content']
// 撤回
todo.revert(["content"]);
// 计数器
post.increment("likes", 1);
// 更新数组
// push
AV.Object.add("arrayKey", value);
// 去重添加,位置随机
AV.Object.addUnique("arrayKey", value);
// 从数组字段中删除指定对象的所有实例,如果是普通数组去掉多个,unique数组只去掉一个
AV.Object.remove("arrayKey", value);
删除
// 删除整个
const todo = AV.Object.createWithoutData("Todo", "582570f38ac247004f39c24b");
todo.destroy();
// 删除某个属性
const todo = AV.Object.createWithoutData("Todo", "582570f38ac247004f39c24b");
// priority 属性会被删除
todo.unset("priority");
// 保存对象
todo.save();
关联
const post = new AV.Object("Post");
post.set("title", "饿了……");
post.set("content", "中午去哪吃呢?");
// 创建 comment
const comment = new AV.Object("Comment");
comment.set("content", "当然是肯德基啦!");
// 将 post 设为 comment 的一个属性值
comment.set("parent", post);
// 保存 comment 会同时保存 post
comment.save();
查询
基础查询
const query = new AV.Query("Student");
// 查询lastName为Simith的
query.equalTo("lastName", "Smith");
query.find().then((students) => {
// students 是包含满足条件的 Student 对象的数组
});
条件查询
// 以下表示and 同时生效
// 不等于
query.notEqualTo("firstName", "Jack");
// 限制 age < 18
query.lessThan("age", 18);
// 限制 age <= 18
query.lessThanOrEqualTo("age", 18);
// 限制 age > 18
query.greaterThan("age", 18);
// 限制 age >= 18
query.greaterThanOrEqualTo("age", 18);
// 最多获取 10 条结果
query.limit(10);
query.first().then((todo) => {
// todo 是第一个满足条件的 Todo 对象
});
// 跳过前 20 条结果
query.skip(20);
// 分页,每页10个,跳过前20个,相当于第三页
const query = new AV.Query("Todo");
query.equalTo("priority", 2);
query.limit(10);
query.skip(20);
// 排序
// 按 createdAt 升序排列
query.ascending("createdAt");
// 按 createdAt 降序排列
query.descending("createdAt");
// 查找包含 'images' 的对象
query.exists("images");
// 查找不包含 'images' 的对象
query.doesNotExist("images");
// 第一个符合条件的title和content
const query = new AV.Query("Todo");
// 确定字段
query.select(["title", "content"]);
query.first().then((todo) => {
const title = todo.get("title"); // √
const content = todo.get("content"); // √
const notes = todo.get("notes"); // undefined
});
字符串查询
// 相当于 SQL 中的 title LIKE 'lunch%'
query.startsWith("title", "lunch");
// 相当于 SQL 中的 title LIKE '%lunch%'
query.contains("title", "lunch");
// 'title' 不包含 'ticket'(不区分大小写)
const regExp = new RegExp("^((?!ticket).)*$", "i");
query.matches("title", regExp);
数组查询
// 数组属性 tags 包含 工作
query.equalTo("tags", "工作");
// 数组属性长度为 3
query.sizeEqualTo("tags", 3);
// 所有数组属性 tags 同时包含 工作、销售 和 会议
query.containsAll("tags", ["工作", "销售", "会议"]);
统计数量
const query = new AV.Query("Todo");
query.equalTo("isComplete", true);
query.count().then((count) => {
console.log(`${count} 个 todo 已完成。`);
});
组合查询
// or
const priorityQuery = new AV.Query("Todo");
priorityQuery.greaterThanOrEqualTo("priority", 3);
const isCompleteQuery = new AV.Query("Todo");
isCompleteQuery.equalTo("isComplete", true);
const query = AV.Query.or(priorityQuery, isCompleteQuery);
// and
const startDateQuery = new AV.Query("Todo");
startDateQuery.greaterThanOrEqualTo(
"createdAt",
new Date("2016-11-13 00:00:00")
);
const endDateQuery = new AV.Query("Todo");
endDateQuery.lessThan("createdAt", new Date("2016-12-03 00:00:00"));
const query = AV.Query.and(startDateQuery, endDateQuery);
注意事项
- 不等于和不包含查询(无法使用索引)
- 通配符在前面的字符串查询(无法使用索引)
- 有条件的 count(需要扫描所有数据)
- skip 跳过较多的行数(相当于需要先查出被跳过的那些行)
- 无索引的排序(另外除非复合索引同时覆盖了查询和排序,否则只有其中一个能使用索引)
- 无索引的查询(另外除非复合索引同时覆盖了所有条件,否则未覆盖到的条件无法使用索引,如果未覆盖的条件区分度较低将会扫描较多的数据)