上周deno第一个版本已经正式发布,目前github上的star已经快突破60K了,趁着这个风口,我也花了半天时间将api全部撸了一遍,在做demo的时候发现了一些问题,今天将我学习过程中踩过的坑和大家说一下,同时也简述一下怎么用deno操作数据库,官方的案例有一个问题,稍后和大家展示。不多说,先上案例。坑我会统一在最后梳理。
// 引入依赖
import { init, MongoClient } from 'https://deno.land/x/mongo@v0.6.0/mod.ts';
// 初始化
await init();
// 创建服务并链接数据库
const client = new MongoClient();
client.connectWithUri("mongodb://localhost:27017");
// 使用runoob数据库
const db = client.database("runoob");
// 使用col表
const col = db.collection("col");
不知道大家注意倒数第二行代码没有,官方的案例是这么写的:
import { init, MongoClient } from "https://deno.land/x/mongo@v0.5.2/mod.ts";
// Initialize the plugin
await init();
const client = new MongoClient();
client.connectWithUri("mongodb://localhost:27017");
const db = getClient().database("test");
const users = db.collection("users");
注意看这个getClient(),全文上下没有一个地方是有定义这个方法的,我也不知道哪里来的,纠结了耗久,我尝试过client.getClient(),这是一个坑。
Deno.openPlugin错误
我们用deno run test.ts运行一下,报错了,错误信息如下:
error: TS2339 [ERROR]: Property 'openPlugin' does not exist on type 'typeof Deno'.
return Deno.openPlugin(localPath);
~~~~~~~~~~
at https://deno.land/x/plugin_prepare@v0.6.0/mod.ts:64:15
这是由于Deno.openPlugin这个api不是稳定版本的原因,解决方法是在文件名前面加上--unstable参数就行,命令:deno run --unstable b.ts。
操作权限不足错误
但是这样还是不够,因为我们知道,deno和node的区别之一是安全策略,也就是说我们要读取文件,修改文件都需要权限才能操作,往数据库中插入数据和查询数据就是文件的读写操作,我们需要相应的权限,所以我们可以用-A参数获取全部权限,最后的命令:deno run -A --unstable b.ts。其中 -A 和 --unstable 可以互换位置,只要在run和文件名中间就行。
数据库操作
插入数据
我们解这往下走,这样控制台出了编译信息以外时看不到任何输出信息的,因为我们并没有输出任何东西,我们尝试往col表中做如下操作(即我们对数据库进行操作):
// 插入一条数据
const insertId = await col.insertOne({
username: "张三",
age: 15
});
// 插入多条数据
const insertIds = await col.insertMany([
{
username: "李四",
age: 15
},
{
username: "王五",
age: 15
}
]);
// 查找全部数据
const data = await col.find({});
console.log(data)
这里提供了插入数据的两个方法以及查询全部数据的方法,插入数据方法返回的是该数据的id。输出结果我们可以看到数据库中确实存在了3条数据。
修改数据
const result = await col.updateOne(
{ username: "张三" },
{ $set: { age: 20 } }
);
const result2 = await col.updateMany(
{ age: 15 },
{ $set: { height: 120 } }
);
const data = await col.find({});
console.log(data)
我们可以看到结果输出中张三的age已经修改为了20,且所以age等于15的数据都加了一条height属性,说明我们修改数据成功了。
(补充:有人会问,代码中的$set是什么鬼,这是mongodb的条件操作符,有兴趣的朋友可以参考MongoDB 条件操作符)
接着正文说,注意,这里又是一个大坑。我们先看看官方写法:
// updateOne
const { matchedCount, modifiedCount, upsertedId } = await users.updateOne(
username: { $ne: null },
{ $set: { username: "USERNAME" } }
);
// updateMany
const { matchedCount, modifiedCount, upsertedId } = await users.updateMany(
username: { $ne: null },
{ $set: { username: "USERNAME" } }
);
如果你这么写,那么控制台会报3个错误。
1、error: TS2304 [ERROR]: Cannot find name 'age'.
2、TS1005 [ERROR]: ',' expected.
3、TS2554 [ERROR]: Expected 2 arguments, but got 3.
啥意思,先不看前两条,就看第三条,解释一下就是说,这个方法需要两个参数,但是传了个,我们再仔细看看JS传参:
function fn (x, y) { return x.value + y.value };
// 正常情况下
fn(
{value: 1},
{value: 2}
);
// 官方传参
fn(
value: 1,
{ value: 2 }
)
如果我们要将对象作为参数传入,必须用{}包起来,官方文档就是犯了这样一个错误。
统计
官方也给了统计的方法,很简单,没有坑,这里就不多说了。
// 统计age小于20的数量
const count = await col.count({ age: { $lt: 20 } });
console.log(count); // 2
聚合
// 统计每个年龄段的学生的数量
const docs = await col.aggregate([
// { $match: { age: 15 } },
{ $group: { _id: "$age", total: { $sum: 1 } } }
]);
console.log(docs);
控制台输出的结果是:
[
{ _id: 15, total: 2 },
{ _id: 20, total: 1 }
]
代表着age为15的有2条数据,age为20的有一条数据。
又来了一个坑。(坑有点多,耐心点),老样子,看看官方的写法。
// aggregation
const docs = await users.aggregation([
{ $match: { username: "many" } },
{ $group: { _id: "$username", total: { $sum: 1 } } }
]);
这样输出的结果就是:
error: TS2551 [ERROR]: Property 'aggregation' does not exist on type 'Collection'. Did you mean 'aggregate'?
简单粗暴的说就是没有'aggregation'这个方法,要你尝试用'aggregate'方法。(官方文档更新不及时啊)。
查询
const data = await col.findOne({ age: 15 });
const data2 = await col.find({ age: 15 });
console.log(data);
console.log(data2);
findOne和find方法唯一不同点就是前者只返回一条数据,后者会返回所有匹配的数据,很简单,这里就不多说了。
删除
const data = await col.deleteOne({ age: 15 });
const data1 = await col.deleteMany({ age: 20 });
const list = await col.find({});
console.log(data);
console.log(data1);
console.log(list);
官方也提供了两个方法,deleteOne和deleteMany,前者只会按照顺序删除一条,而后者会删除所有匹配的数据,返回的结果都是删除的数据数量,如果成功,前者返回的永远是1,后者就要看你删除了多少条匹配的数据了,这里没有坑,就不多解释了。
大坑梳理
1、Deno.openPlugin错误
解决方法:在run和文件名之间加入 --unstable 参数,例如:deno run --unstable b.ts
2、权限问题
解决方法:在run和文件名之间加入相应参数或 -A 参数,例如:deno run -A --unstable b.ts,-A参数会获取全部权限。
3、修改数据时参数数量错误问题(Expected 2 arguments, but got 3)
解决方法:将第一个参数用{}包起来,如:
const result = await col.updateOne(
{ username: "张三" },
{ $set: { age: 20 } }
);
4、aggregation报错问题
解决方法:将aggregation替换为aggregate。
好了,林林总总中遇写完了,最后附上mongo依赖的官方地址:mongo