文章目录
什么是mongodb?
MongoDB 是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
下载地址
mongodb的特点:
它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:
*面向集合存储,易存储对象类型的数据。
*模式自由。
*支持动态查询。
*支持完全索引,包含内部对象。
*支持查询。
*支持复制和故障恢复。
*使用高效的二进制数据存储,包括大型对象(如视频等)。
*自动处理碎片,以支持云计算层次的扩展性
*支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
*文件存储格式为BSON(一种JSON的扩展)。
*可通过网络访问。
mysql与mongodb数据的对比
mysql是关系型数据库,数据库下有数据表
mongodb是非关系型数据库,它有类似于数据表的集合
MongoDB 的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)和传统的RDBMS 系统(具有丰富的功能)之间架起一座桥梁,它集两者的优势于一身。
mongodb适用场景
● 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
● 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。
● 大尺寸、低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
● 高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。
● 用于对象及JSON 数据的存储:Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。
Mongo不适用的场景如下:
- 要求高度事务性的系统。
- 传统的商业智能应用。
- 复杂的跨文档(表)级联查询。
mongodb基本使用:
- 查看数据库:
show dbs
- 创建数据库:
use 数据库名
(如果没有会创建,如果有则不会) - 查看当前数据库:
db
- 查看集合:
show collections
- 创建集合:
db.createCollection('集合名称')
- 插入数据/文档:
db.集合名.insert({键:值,键:值})
- 查询数据:
db.集合名.find()
- 删除集合:
db.集合名.drop()
- 删除数据库:
db.dropDatabase()
mongodb的主键:_id
可以自定义。
默认情况下,主键是一个objectId类型的数据。
主键是一个12个字节的bson类型字符串,分别是:
4个字节 存储数据的时间戳
3个字节 存储数据的电脑的标识符
2个字节 存储数据的mongoDB的进程id
3个字节 计时器
插入文档
写入一个:
db.集合名.insertOne(文档内容,{writeConcern:<document>})
eg:db.person.insertOne({name:"zs",gender:"男"})
db.集合名.save(文档内容,{writeConcern:<document>})
eg:db.person.save({name:"zs",gender:"男"})
//writeConcern是安全级别,默认情况下,会有安全级别,安全级别越高消耗性能越大。
insertOne和save如果集合不存在,则会自动创建集合
区别:如果insertOne如果数据存在会报错(一般是主键重复),save则会覆盖数据
写入多个:
db.集合名.insertMany([文档内容,文档内容],{
writeConcern:<document>,
ordered:<boolean>
})
eg:db.person.insertMany([{_id:1,name:"zs",gender:"男"},{_id:2,name:"zz",gender:"男"},{_id:3,name:"zw",gender:"男"}],{ordered:true})
db.集合名.insert() //和insertMany一样
ordered:是否按顺序写入(默认为false)
注意点:如果ordered为true,前面的文档出错,后面的所有的文档都不会被写入。
如果ordered为false,前面的文档出错,后面的所有的文档可以被写入。(出错的文档不会被写入)
查询文档
db.集合名.find(<查询条件>,<投影文档>)
查询条件:相当于mysql的where,根据条件查询
投影条件:相当于mysql的select,选择指定字段
查询条件:
eg:db.person.find({name:'zs',gender:"男"})
//默认是要满足这些条件,冒号相当于=关系,查询条件没有顺序要求
eg:db.person.insert(
{name:'zs',gender:'男',parent:{name:'ls',gender:'男'}})
eg:db.person.find({'parent.name':'ls'})
//当要查找的字段是一个文档里的字段,"字段.文档属性名称"
投影条件:
//如果不想查询那个字段把那个字段设为0,为1时会查询该字段,默认所有字段为1
eg:db.person.find({},{_id:0,name:1,gender:1})
//除_id以外,其他所有字段不能同时为0和1
eg:db.person.find({},{name:1,gender:0})//会报错!!
比较操作符:
$eq:等于, $ne:不等于
$gt:大于, $gte:大于等于
$lt:小于, $lte:小于等于
$in:匹配和任意指定值相等的文档,相当于or(满足一个)
$nin:匹配和任意指定值都不相等的文档(所有的值都不满足条件才会被查询出来)
eg:db.person.find({name:{$eq:'zs'}})//取出name等于zs的数据
db.person.find({name:{$in:['zs','zw']}})//匹配name等于zs或者等于zw的数据
//使用:字段:{操作符:‘值’}
其中$ne, $nin不只是不等于,也包含没有值的,或值为空的,比如
如果在数据库插入:{name:'zl'}
db.person.find({gender:{$ne:'男'}}
//这条语句会把name:'zl',这条数据查出来。
逻辑操作符:
$not:匹配条件不成立的文档
$and:匹配条件全部成立的文档
$or:匹配至少一个条件成立的文档
$nor:匹配多个条件都不成立的文档
其中 $not, $nor与 $ne, $nin一样,没有值也成立
$or相当于 $in, $nor相当于 $nin
db.person.find({gender:{$not:{$eq:"男"}}})//匹配gender不等于男的文档
db.person.find({$and:[{name:{$eq:'zs'}},{gender:{$eq:'男'}}]})
//查询满足name=zs和gender=男的文档
字段操作符
$exists:查询包含某个字段的文档
$type:查询指定字段包含指定类型的文档
db.person.find({gender:{$exists:true})
//查询包含gender字段的文档,应用:数据筛选
db.person.find({gender:{$ne:'男',$exists:true})
//查询gender不等于男并且存在
db.person.find({gender:{$type:'string'}})
//查询gender字段值的类型为字符串型的文档
数组操作符和运算操作符
$all:匹配数组中包含所有指定查询值文档
$eleMatch:匹配数组至少有一个能完全匹配所有的查询条件的文档
db.person.insert([
{name:'zs',book:['math','english','physical']}
])
eg:db.person.find(book:{$all:['math','physical']})
//查询book中同时拥有:math和physical的文档
db.person.insert([
{
name:'zs',book:[{name:'math',price:21},
{name:'english',price:22},
{name:'physical',price:23}]
},
{
name:'zl',book:[{name:'math',price:12},
{name:'english',price:13},
{name:'physical',price:14}]
}
])
eg:
db.person.find({book:{$eleMatch:['book.name':'math','book.price':12]}})
//必须同时满足book.name为'math',book.price'为12才被查询
$regex:匹配符合正则表达式的文档
eg:db.person.find({name:{$regex:/^z/,$option:'i'}})
//匹配名字包含z的文档
eg:db.person.find({name:{$in:[/^z/i,/^w/i]}})
//匹配名字包含z或w的文档
文档游标
文档游标保存着数据的地址,相当于指针。
mongodb支持js代码。
文档游标十分钟没有操作就会自动关闭
阻止关闭:noCursorTimeout()
close()手动关闭
var cur=db.person.find()
//定义变量cur存储find查找的结果,可以使用cur[0]来访问文档
hasNext() 查看有没有下一个返回true或false
cur.foreach(printjson) //可以遍历查找到的数据
分页、排序方法(在文档游标上使用)
limit(number):取多少个文档
skip(offset):跳过文档
sort(field:ordering):排序,ordering为1是升序,ordering为-1是降序
count(applyskiplimit):统计函数,统计集合文档的个数,applySkipLimit表示是否忽略skip和limit,默认为false。在分布式服务器使用count最好在find里加条件。
eg:var cur=db.person.find()
db.person.find().limit(3)//取3个文档
cur.skip(3)//跳过3个文档
//可以链式调用
eg:db.person.find().skip(3).limit(3)
//跳过3个文档取3个文档
eg:db.person.find().sort({age:1})
//按年龄进行升序排序,可以多字段排序
/*注意点:如果skip、limit、和sort同时使用时,
无论那个先使用,都按照sort、skip、limit这个顺序执行,即先排序再跳过最后再
取出想要的个数*/
eg:db.person.find().skip(3).count({applySkipLimit:true})
//忽略前三条,统计文档个数
更新文档
更新方法:save():新增/覆盖文档,如果_id存在就是覆盖
update({filter},{update},{option})
filter:筛选条件
update:更新内容
option:额外配置
默认情况下,update方法也是覆盖
eg:db.person.update({name:'zs'},{gender:'女'},{})
//把name为zs的文档的gender改为女,由于是覆盖,所以name就会不见
//注意点:如果update在更新内容指定了_id则要保证_id和原文档一致。
更新操作符:
$set:更新字段,如果字段不存在就是增加字段。注意:是更新不是覆盖
eg:db.person.update({name:'zs'},{$set:{gender:'女'}})
//把name为zs的文档的gender改为女,name不会消失
update默认情况下只会修改满足条件的第一个文档,如果想更新所有满足条件的文档
要指定第三个参数multi,而且第二个参数要使用更新操作符。
eg:db.person.update({name:'zs'},{$set:{gender:'女'}},{multi:true})
//把所有name为zs的文档的gender改为女
db.person.insert([
{name:'zs',book:['math','english','physical']}
])
更新数组/对象字段:
eg:db.person.update({name:'zs'},{$set:{'book.1':'chinese'}})
/*把数组中book下的english修改为chinese,
修改方法:$set:{book.下标:值},
如果是对象,则是$set:{book.属性名:值}*/
如果操作的数组字段的索引不存在,会自动新增:
eg:db.person.update({name:'zs'},{$set:{'book.3':'chinese'}})
//把book第4个元素设为chinese,由于没有第4个,所以会自动新增
如果操作的数组字段的索引不存在且中间隔多个索引,则中间会自动用null填充
eg:db.person.update({name:'zs'},{$set:{'book.6':'chinese'}})
/*把book第7个元素设为chinese,
由于第7个前面也没有元素,所以会自动新增多个null*/
$unset:删除字段
eg:db.person.update({name:'zs'},{$unset:{gender:''}})
//把name为zs的gender字段删除,在gender后面无论赋什么值都会删除
注意点:如果删除数组字段中的元素,不会修改数组的长度,而是置为null
$rename:重命名字段
使用: $rename:{旧字段:新字段}
如果要操作的字段不存在,就没有什么操作。
如果修改后的字段已经存在,那么另外一个同名字段就会被删除
$rename不能操作数组,即使数组里也是文档也不能修改数组里的字段名
eg:db.person.update({name:'zs'},{$rename:{gender:'age'}})
//把name为zs的gender字段改为age
eg:db.person.insert(
{name:'zs',
book:[{name:'math',price:100},{name:'english',price:80}]}
)
//book里的name字段名不能修改
$rename可以将外层字段和内层字段互相转移
db.person.insert({name:'zs',book:{name:'math'}})
eg:db.person.update({name:'zs'},{$rename:{name:'book.person'}})
//将name转移到book中
$inc:字段值做加上或者减去值,正数为加,负数为减
$mul:字段值乘或除以值,大于1是乘,小于1是除
(操作字段必须为数值)
如果操作字段不存在会自动新增。( $inc为操作值, $mul为0)
eg:db.person.update({name:'zs'},{$inc:{age:-3}})
//给zs的age减去3
$min:比较并保留较小的值
$max:比较并保留较大的值(不一定是数值)
注意点:1、如果字段不存在就会增加该字段
2、不同数据类型也可以做比较
mongodb的默认排序规则(从小到大):
Null
Number (ints , longs , doubles , decimals)
Symbol , String
Object
Array
BinData
ObjectId
Boolean
Date
Timestamp
Regular Expression
eg:db.person.update({name:'zs'},{$min:{age:30}})
//和name为zs的age比较,如果30小就把age修改为30,否则不修改
eg:db.person.update({name:'zs'},{$min:{name:'jj'}})
//和name为zs的name做比较,结果是保留jj
$addToSet:向数组字段添加元素
$push:向数组字段添加元素(不去重)
$pop:从数组字段中删除元素(只能最后一个(1)或第一个(-1))
$pull:从数组字段中删除特定元素(1、支持正则表达式 2、如果删除的是一个数组,就必须一模一样【主要指数组元素顺序】才可以删除,如果是文档可以不需要一模一样【就是字段缺少也是可以的】)
$pullAll:从数组字段中批量删除特定元素(如果删除的是一个数组,就必须一模一样【主要指数组元素顺序】才可以删除,如果是文档也需要一模一样)
db.person.insert([
{name:'zs',book:['math','english','physical']}
])
eg:db.person.update({name:'zs'},{$addToSet:{book:'chinese'}})
//给name为zs的book数组添加chinese
1如果操作的字段不存在,会新增字段,并把值赋给数组
eg:db.person.update({name:'zs'},{$addToSet:{parent:'zl'}})
2如果给数组字段添加文档类型或者数组,就要一模一样才会去重(即使是顺序也
不能更换)
//一般增加进去的数组就是一个元素,如果想一个一个加进去就要使用$each
eg:db.person.update({name:'zs'},{$addToSet:{book:{$each:['chemical
','biological','history']}}})
//会将数组一个一个插入book字段
$push:
eg:db.person.update({name:'zs'},{$push:{book:'chinese'}})
$pop:
eg:db.person.update({name:'zs'},{$pop:{book:1}})
//删除book最后面一个
eg:db.person.update({name:'zs'},{$pop:{book:-1}})
//删除book最前面一个
//通过$pop删除数组即使数组空了字段也没有被删除
$pull:
eg:db.person.update({name:'zs'},{$pull:{book:'math'}})
//删除name为zs的book中的math
$pullAll:
eg:db.person.update({name:'zs'},{$pullAll:{book:['chemical
','biological','history']}})
//删除name为zs的book中的chemical,biological,history
$:更新数组满足特定条件的元素(第一个)
$[ ]:更新数组中所有元素(多个)
eg:
db.person.update({name:'zs',book:'english'},{$set:{'book.$':'chinese'}})
//把name为'zs'且book为'english',english更改为chinese
//$表示复用{name:'zs',book:'english'}(复用筛选条件)
eg:db.person.update({name:'zs'},{$set:{'book.$[]':'chinese'}})
//把所有满足name为zs的数组元素改为chinese
删除文档
remove({query},{option})
query:筛选条件
option:额外配置
option:justOne:只删除第一个满足条件的数据
eg:db.person.remove({name:'zs'})
//删除name为zs的文档,默认删除多条
eg:db.person.remove({name:'zs'},{justOne:true})
//删除name为zs的第一条文档,
eg:db.person.remove({})//删除所有文档
聚合操作
聚合操作:通过一个方法完成一系列操作。(就是把自定义查询过程)
聚合操作的每一个操作被称为一个阶段
聚合操作格式:db.集合名。aggregate([< pipeline>,< options>])
pipeline:定义每个阶段操作
options:额外配置
$project:对文档再次进行投影
db.person.insert([{name:'zs',book:['math','english','physical']}])
eg:db.person.aggregate([
{$project:{
_id:0,
mybook:'$book.0'
}}])
//查询文档并把book字段修改为mybook字段
//聚合操作不会修改原来的文档,而是返回新的文档
$match:筛选符合条件的文档
eg:db.person.aggregate([
{$match:{
'book.0':'math'
}},
{$project:{
_id:0,
myname:'name'
}}
])
//查询book第一个元素为math的文档,然后进行投影
$limit 和 $skip $ sort:和limit、skip、sort一样
db.person.aggregate([
{$limit:1},
{$skip:0},
{$sort:{name:1}}
])
//跳过一个文档取一个文档并降序排列
$unwind:展开数组字段
db.person.insert([{name:'zs',book:['math','english','physical']}])
eg:db.person.aggregate([
{$unwind:{path:'$book'}}
])
//依次为数组中的元素创建一个文档
eg:db.person.aggregate([
{$unwind:{path:'$book',
includeArrayIndex:'index'}}
])
//依次为数组中的元素创建一个文档并给一个下标
注意点:如果文档中没有需要操作的数组字段或者数组没有元素或者数组为null,
会自动将数组过滤掉。
如果不需要过滤掉则需要增加参数preserveNullAndEmptyArrays:true
eg:db.person.aggregate([
{$unwind:{path:'$book',
includeArrayIndex:'index',
preserveNullAndEmptyArrays:true}}
])
$lookup:关联查询
格式:
{ $lookup:{
from:关联集合名称
localField:当前集合字段名
foreignField:关联集合字段名
as:需要输出的字段名
}}
db.person.insert([{name:'zs',book:['math','english','physical']}])
db.book.insert([{name:'math',price:100},
{name:'english',price:110},
{name:'physical',price:120},
])
db.person.aggregate([
{$lookup:{
from:'book',
localField:'book',
foreignField:"name",
as:'date',(保存文档字段)
}}])
//把person的book和book的name进行比较,并查询出来保存在date
$group:对文档进行分组
格式:
{ $group:{
_id:按照什么进行分组,
新字段:其他操作的新字段
}}
eg:db.person.aggregate([
{$group:{
_id:'$gender',
count:{$sum:'$gender'}
}])
//对性别进行分组,并统计各性别人数
$out{‘新集合名’}:将前面操作的节点写入一个新的集合
注意:如果不出现就会新建,如果存在就会覆盖
eg:db.person.aggregate([
{$group:{
_id:'$gender',
count:{$sum:'$gender'}
},
{$out:'genderCount'}
])
//操作完后写入genderCount集合里
$convert:将不同数据类型强制为一个数据类型
格式:{
$convert:{
input:‘需要转化的数据类型’,
to:‘转化之后的数据类型’,
onError:‘转化失败之后的报错’,
onNull:‘没有数据的报错’,
}}
db.person.insert([{name:'zs',time:'2020-10-10 00:04:23 +0800'}])
eg:db.person.aggregate([
{$project:{
_id:0,
time:{
$convert:{
input:'$time',
to:'date',
onError:'转化失败',
onNull:'没有数据'
}}}}])
索引
索引:可以用于提升查询速度,默认mongoDB会自动创建索引,是主键的索引,对于排序字段刚好是索引字段会大大提升排序效率
获取索引:db.集合名.getIndexes()
创建索引:db.集合名.createIndex({ 指定索引的字段名},{额外配置})
eg:db.person.createIndex({name:1})
//给name添加一个升序的索引
如何知道查询有没有使用索引?
db.person.explain().find(name:'zs')
winningplan->stage->collscan->遍历集合查询
winningplan->stage->ixscan->索引查询
复合索引:多个字段创建索引
多键索引:为每一个数组元素都创建一个索引
eg:db.person.createIndex({name:1,gender:-1})
//创建name升序,gender降序索引
/*复合索引只支持前缀查询,即如果索引字段为a b c,那么a,ab、abc为索引查询
bc、c不是使用索引查询
*/
唯一索引:如果该字段取值是唯一的可以手动添加唯一索引
eg:db.person.createIndex({name:1},{unique:true})
//给name添加一个唯一索引
如果给一个字段添加唯一索引该字段没有内容,第一次可以添加,第二次就不能添加
db.person.insert([{gender:'男'}])//可以添加,name自动填充为null
db.person.insert([{gender:'男'}])//不能添加,已经存在。
添加唯一索引的组合不能重复添加
db.person.insert([{name:'ls',gender:'男'}])
db.person.insert([{name:'ls',gender:'男'}])//不能添加
db.person.insert([{name:'ls',gender:'女'}])//可以添加
稀疏索引:对文档中不存在的字段数据不启用索引。默认值是 false。
eg:db.person.createIndex({name:1},{spare:true})
删除索引:db.集合名.dropIndex(‘索引名称或定义’)
getIndexes()的name可以获取索引的名称
db.person.dropIndex({name:1})//定义删除
多表查询
文档之间关系:1内嵌式
优势:一次查询就能拿到所有数据
劣势:如果数据比较复杂就不方便管理和更新,冗余数据较多
2规范式
优势:如果数据比较复杂,也方便管理和更新,冗余数据较少
劣势:不方便查询
内嵌式:将一个文档嵌入另一个文档
{
name:'zs',
age:'18',
card:{
num:2122313124124123,
date:0702,
}
}
//name为zs有一张生日卡
规范式:将文档放在不同的集合中,通过某个字段建立文档关系。
{
_id:1,
num:2122313124124123,
date:0702,
}
{
name:'zs',
age:18,
cardid:1
}
一对一关系
eg:一个人有张身份证
内嵌式:
db.person.insert({ name:'zs',
age:'18',
card:{
num:2122313124124123,
date:0702,
}})
db.person.find({name:'zs'})
规范式:
db.card.insert({
_id:1,
num:2122313124124123,
date:0702,
})
//身份证集合
db.person.insert({ _id:2,
name:'zs',
age:18,
cardid:1
})
//人集合
db.person.aggregate([
{$lookup:{
from:'card',
localField:'cardid',
foreignField:"_id",
as:'card',(保存文档字段)
}}])
//查询人对应的身份证
一对多关系
eg:一个人有多本书
内嵌式:
db.person.insert({
name:'zs',
age:'18',
book:[{name:'math',price:100},
{name:'physical',price:90}
]})
db.person.find({name:'zs'})
规范式:
db.books.insert([{_id:1,
name:'math',
price:100,
},{ _id:2,
name:'physical',
price:90,
}])
//书集合
db.person.insert({ _id:111,
name:'zs',
age:18,
booksid:[1,2]
})
//人集合
db.person.aggregate([
{$lookup:{
from:'books',
localField:'booksid',
foreignField:"_id",
as:'books',
}}])
多对多关系
eg:一个学生有多个老师,一个老师有多个学生
内嵌式:
db.student.insert({
name:'zs',
age:'18',
teacher:[{name:'mathTeacher'},{name:'physicalTeacher'}]})
db.teacher.insert({
name:'ls',
age:'38',
student:[{name:'zs'},{name:'zl'}]})
db.student.find({name:'zs'})
db.teacher.find({name:'ls'})
//分别将信息存入自己的集合
规范式:
db.teacher.insert([{_id:1,name:'ls'},{_id:2,name:'ww'}])
db.student.insert({_id:3,name:'zs'},{_id:4,name:'zl'}])
db.real.insert([{stuid:3,teacherid:1},{stuid:3,teacherid:2}])
//将学生信息写在一个集合,将老师信息写在一个集合,再来一个集合作为关系的集合
db.student.aggregate([
{$lookup:{
from:'real',
localField:'_id',
foreignField:"stuid",
as:'real',
}}])
//查询zs有哪些teacher,只能知道id,如果需要更详细的信息就继续执行下面这个
{$lookup:{
from:'teacher',
localField:'real.teacherId',
foreignField:"_id",
as:'teachers',
}
Mongoose
Nodejs操作mongoDB的对象模型工具
中文官网
英文官网
mongoose中js的一个模型对于数据库中一个集合,
一个对象对于一个文档,
对象的一个属性对应一个字段
使用:
1定义集合规则
2利用规则创建一个集合
3创建一个文档
4操作文档
const mongoose = require('mongoose');//导入mongoose
mongoose.connect('mongodb://ip地址:端口/数据库名');//连接数据库
//判断连接是否成功
let db = mongoose.connection;
db.on('error',(err)=>{
console.log(err,"连接失败")
});
db.once('open', function() {
console.log("连接成功")
});
db.once('close', function() {
console.log("连接成功")
});
//定义集合规则
var person = mongoose.Schema({
name:String,
gender:String,
});
//利用规则创建一个集合
//只要创建好模型,就可以使用person操作集合
var person = mongoose.model('person',person);
//创建一个文档
//只要创建好对象,就可以操作文档
const zs = new person({name:'zs',gender:'男'})
//操作文档(可以通过回调,或者返回一个promise)
zs.save((err,zs)=>{
if(!err){
console.log("保存成功")
}
})
//增加
zs.create({name:'ls',gender:"男"},(err,result)=>{
if(!err){
console.log("插入成功")
}
})
//查询
(async ()=>{
let result=await zs.find({过滤条件},{投影条件},{额外配置})
console.log(result)
})()
//查询并拿到结果
zs.update({筛选条件},{更新内容},{额外配置}(err,result)=>{
console.log(result)
})