ArangoDB教程: Node.js 10分钟
这是一个关于Node.js 操作ArangoDB 的简短教程。在不到10分钟的时间内,您将学会如何在Linux或OSX 上通过Node 操作ArangoDB。
安装JavaScript 驱动程序
首先让我们从NPM安装 ArangoDB JavaScript 驱动程序 :
1 2 |
npm install arangojs@5 |
如果要使用当前目录之外的驱动程序,您也可以通过使用 --global 标识来安装:
1 2 |
npm install --global arangojs@5 |

快速开始
您可以通过使用命令行中的Node shell来继续本教程:
1 2 |
node |
要使用客户端,您可以使用 require
导入它:
1 2 |
Database = require('arangojs').Database; |

使用一个句柄
要有效地进行学习,我们需要一个在现有的ArangoDB数据库中的句柄。
让我们通过使用连接字符串创建一个新的数据库
来实现这一点:
1 2 |
db = new Database('http://127.0.0.1:8529'); |
此连接字符串实际上表示默认值,因此您可以省略它:
1 2 |
db = new Database(); |
如果这还是太冗长,你可以直接调用驱动:
1 2 |
db = require('arangojs')(); |
三个调用中的任何一个的结果都应该是相同的。

创建数据库
我们不想破坏任何现有的数据,所以让我们先创建一个名为“mydb”的新数据库:
1 2 3 4 5 |
db.createDatabase('mydb').then( () => console.log('Database created'), err => console.error('Failed to create database:', err) ); |
因为我们正在尝试在服务器上执行一些操作,所以这个动作是异步的。
ArangoDB驱动程序中的所有异步方法return promises,但您也可以通过用节点式回调代替:
1 2 3 4 5 |
db.createDatabase('mydb', function (err) { if (!err) console.log('Database created'); else console.error('Failed to create database:', err); }); |
请注意,您创建的新数据库仅在调用回调或promise resolved 后才可用。
在本教程中,我们将使用promise API,因为它们可以在最新版本的Node.js 以及大多数现代浏览器中使用。

切换到新的数据库
我们创建了一个新的数据库,但是我们还没有告诉驱动程序它应该开始使用它。现在我们来更改一下:
1 2 |
db.useDatabase('mydb'); |
这个方法可以被立即执行。
句柄“db”现在引用“mydb”数据库,而不是之前引用的(默认)“_system”数据库。

另一个句柄
集合 是存储现有数据的地方。
实际上有两种类型的集合,但是现在我们只需要一个集合。
像数据库一样,在执行任何操作前您首先需要一个句柄:
1 2 |
collection = db.collection('firstCollection'); |
再次看到它会立即执行。
与数据库不同,在创建句柄之前,集合没有必要已经一定存在。

创建集合
我们有一个句柄,但为了将实际的数据放在集合中,我们需要创建一个集合:
1 2 3 4 5 |
collection.create().then( () => console.log('Collection created'), err => console.error('Failed to create collection:', err) ); |
一旦promise resolves,集合句柄将指向一个实际的集合,在那里我们可以存储数据。

创建文档
没有数据的集合是没有意义的。所以我们先来定义一个我们要存储的数据:
1 2 3 4 5 6 7 |
doc = { _key: 'firstDocument', a: 'foo', b: 'bar', c: Date() }; |
集合条目(在ArangoDB中称为文档 )是纯JavaScript对象,可以包含可以存储在JSON字符串中的任何内容。
您可能对_key
属性感到疑惑:某些以下划线开头的属性名称在ArangoDB中是有特别意义的,在之后密钥被用来识别该文档。
如果您没有自己指定密钥,ArangoDB将为您生成一个密钥。

保存和更新文档
ArangoDB还会添加一个_rev
属性,它在每次文档写入时都会发生变化。一个_id
,由集合名称和文档键组成。
每次直接创建,更新,替换或获取文档时,都会返回这些“meta”属性。
我们在实例中看一下,首先保存文档::
1 2 3 4 5 |
collection.save(doc).then( meta => console.log('Document saved:', meta._rev), err => console.error('Failed to save document:', err) ); |
…然后更新到位:
1 2 3 4 5 |
collection.update('firstDocument', {d: 'qux'}).then( meta => console.log('Document updated:', meta._rev), err => console.error('Failed to update document:', err) ); |
请注意,两个_rev
值是不同的。
您可以通过提取来查看完整的文档(使用键,ID和更新的_rev) :
1 2 3 4 5 |
collection.document('firstDocument').then( doc => console.log('Document:', JSON.stringify(doc, null, 2)), err => console.error('Failed to fetch document:', err) ); |

删除文档
我们已经在这个文件上做了很多操作,所以现在我们来看看怎么将它删除掉:
1 2 3 4 5 |
collection.remove('firstDocument').then( () => console.log('Document removed'), err => console.error('Failed to remove document', err) ); |
一旦 promise resolved 了,该文件就不复存在了。
我们可以通过尝试再次提取,来验证这个(这会导致错误):
1 2 3 4 |
collection.document('firstDocument').then( doc => console.log('Document:', JSON.stringify(doc, null, 2)), err => console.error('Failed to fetch document:', err.message)); |
如果您看到提示错误消息“找不到文档”,那我们就成功了。

批量导入
在我们继续之前,我们需要一些更有趣的示范数据:
1 2 3 4 5 |
docs = []; for (i = 0; i < 100; i++) { docs.push({_key: `doc${i + 1}`, value: i}); } |
将这些数据一个一个导入将是相当乏味的,所以让我们使用导入方法:
1 2 3 4 5 |
collection.import(docs).then( result => console.log('Import complete:', result), err => console.error('Import failed:', err) ); |

简单查询
查看目前小集合中内容的最简单的方法是,使用“all”查询:
1 2 3 4 5 6 7 |
collection.all().then( cursor => cursor.map(doc => doc._key) ).then( keys => console.log('All keys:', keys.join(', ')), err => console.error('Failed to fetch all documents:', err) ); |
这将有助于避免在使用大量结果集时不必要的内存混乱。
与光标对象的所有交互都是异步的,因为驱动程序将根据需要自动从服务器获取附加数据。
需要注意的是,与数组不同,光标使用后将会耗尽。
它们是一次性使用的项目,不是永久的数据结构。

AQL查询
简单的查询既有意义但又是有限的。
与其返回每一个整个文档并在本地提取其密钥,我们来编写一个查询,并在ArangoDB 中执行它。
此外,我们按价值对它们进行排序,这样我们将可以避免无序的混乱:
1 2 3 4 5 6 7 |
db.query('FOR d IN firstCollection SORT d.value ASC RETURN d._key').then( cursor => cursor.all() ).then( keys => console.log('All keys:', keys.join(', ')), err => console.error('Failed to execute query:', err) ); |
请注意,我们仍然会收到一个游标,但不再需要处理结果本身。
我们将使用“all”方法容易地将游标转换为数组,以获取所有结果。

模板字符串
当编写复杂的查询时,您不需要在巨大的字符串中对所有内容进行硬编码。
驱动程序提供了同样的 aqlQuery
模板处理程序,您也可以在ArangoDB中使用它:
1 2 |
aqlQuery = require('arangojs').aqlQuery; |
您可以使用它来编写AQL模板。
任何在AQL模板中引用的变量都将自动添加到查询的绑定值中。
它甚至知道如何处理集合句柄。
让我们通过编写一个 INSERT
查询来证明这一点,这个查询会使用AQL创建一个新文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
db.query(aqlQuery` FOR doc IN ${collection} LET value = 100 + doc.value INSERT { _key: CONCAT("new", doc.value), value } INTO ${collection} RETURN NEW `).then( cursor => cursor.map(doc => doc._key) ).then( keys => console.log('Inserted documents:', keys.join(', ')), err => console.error('Failed to insert:', err) ); |
请注意,在AQL中,特殊的 NEW
变量是指新创建的文档。

在AQL中更新文档
我们已经学了如何使用AQL创建新文档,确保教程完整性,我们再来看看如何更新它们:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
db.query(aqlQuery` FOR doc IN ${collection} UPDATE doc WITH { value: doc.value * 2 } IN ${collection} RETURN {old: OLD.value, new: NEW.value} `).then( cursor => cursor.map(doc => `${doc.old} => ${doc.new}`) ).then( results => console.log('Update complete:', results.join(', ')), err => console.error('Update failed:', err) ); |
因为 UPDATE
(和 REPLACE
)会修改现有文档,
AQL还提供了特殊的 OLD
变量来指代文档的先前状态。
当 REPLACE
用新的文档完全替换现有文档(仅保留其密钥)
UPDATE
操作将将新对象合并到现有文档中。
任何未被显式覆盖的现有属性保持不变。

在AQL中删除文档
有时侯数据较少反而比较多更好。
我们通过删除一部分数据的来修剪我们的集合:
1 2 3 4 5 6 7 8 9 10 11 12 |
db.query(aqlQuery` FOR doc IN ${collection} FILTER doc.value % 10 != 0 REMOVE doc IN ${collection} RETURN OLD._key `).then( cursor => cursor.all() ).then( keys => console.log('Removed:', keys.join(', ')), err => console.error('Failed to remove:', err) ); |
这一次AQL不会呈现一个 NEW
,因为这个文件将会消失。
但是,您仍然可以通过 OLD
最后一次查看,并和文档道别。

删除所有文档
进行了这么多操作,现在让我们来删除文档。
完全清空集合的方法称为“truncate”::
1 2 3 4 5 |
collection.truncate().then( () => console.log('Truncated collection'), err => console.error('Failed to truncate:', err) ); |
请注意,不会有任何返回信息。
当您truncate一个集合,您将丢弃其中所有的内容。
这一操作是不可撤销的:
1 2 3 4 5 6 7 |
collection.all().then( cursor => cursor.all() ).then( results => console.log('Collection contains', results.length, 'documents'), err => console.error('Failed to fetch:', err) ); |
请注意,您还可以truncate 数据库。
不必要担心您的集合,因为truncate 只会删除文档。
即便如此,您也不想草率对待。

学习更多
到目前为止,您应该了解了如何在Node中使用ArangoDB
但是您还可以了解更多,还有更多的可以做:
- 了解有关 AQL 来了解有关查询语言的更多信息
- 如果要从Node(或甚至从浏览器中!)使用ArangoDB,请了解更多关于驱动程序 API
- 了解ArangoDB Shell 来更好地了解ArangoDB
- 了解如何通过 ArangoDB Foxx 来用JavaScript 扩展ArangoDB
- 了解ArangoDB Cookbook 查看常见问题的实际解决方案
- 被术语困惑了吗?有一个术语表可以帮助你
- 你知道ArangoDB 2.8将 图形查询融合到AQL吗?
- 有问题吗?在 StackOverflow 找到答案
- 做了一件很酷的事情,通过邮件列表告诉我们
- 想参与到其中? ArangoDB是开源的,有很多方式可以做出贡献
- 还有困惑吗?联系Slack社区 或者 Twitter @arangodb
This page has been translated from the original English version with great caution.
However, it might still contain mistakes. Please refer to the English version for binding information.