在本教程中,我们将看看如何创建一个简单的应用程序来跟踪观察列表或投资组合中的股票。为了存储这些数据,我们将使用MongoDB--一种流行的NoSQL存储解决方案,经常与Node.js一起使用。我们将看到如何创建目录结构来保存这个股票观察列表应用程序,然后使用npm安装MongoDB Native,将其作为一个依赖项保存在package.json文件中。一旦一切就绪,我们将看到如何连接到Mongo并在我们的观察列表中插入一只新的股票。我们将讨论一下ObjectId以及它在Mongo中是如何工作的,然后以获取文件、计算文件、更新文件以及删除文件来结束。
创建目录和Package.json
首先,我们将创建一个简单的目录来保存我们所有的代码,并使用npm init构建package.json文件。
node $mkdir stock-app
node $cd stock-app
stock-app $npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (stock-app)
version: (1.0.0)
description: Simple Stock Watchlist
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to C:nodestock-apppackage.json:
{
"name": "stock-app",
"version": "1.0.0",
"description": "Simple Stock Watchlist",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes)
stock-app $
安装MongoDB Native
现在我们有一个package.json文件,我们可以像这样安装MongoDB Native包。
stock-app $npm install mongodb --save
npm notice created a lockfile as package-lock.json. You should commit this file.npm WARN stock-app@1.0.0 No repository field.
+ mongodb@3.1.1
added 7 packages from 5 contributors and audited 7 packages in 3.009s
found 0 vulnerabilities
完成后,你会在目录中看到一个新的package.json文件,它看起来就像这样。
{
"name": "stock-app",
"version": "1.0.0",
"description": "Simple Stock Watchlist",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"mongodb": "^3.1.1"
}
}
使用MongoClient连接到MongoDB
我们将把我们的数据库特定文件放在一个名为database 的专用目录中。我知道,很有创意。

在这个新目录中,我们可以创建一个名为mongodb-connect.js的JavaScript文件。

在这个文件中,让我们添加以下JavaScript代码。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
client.close();
});
在我们运行这个片段之前,请确保你的机器上已经安装并运行了MongoDB。只要检查出来,我们就可以cd到那个数据库文件夹,然后直接运行这个文件。
stock-app $cd database
database $node mongodb-connect.js(node:14560) DeprecationWarning: current URL string parser is deprecated, and wi
ll be removed in a future version. To use the new parser, pass option { useNewUr
lParser: true } to MongoClient.connect.
Connected to MongoDB
有趣的是。看起来我们确实连接了,但是我们也看到了那个废弃警告。在Stack Overflow上的快速搜索表明,我们可以像这样更新代码--这确实使错误变得清晰。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
client.close();
});
使用MongoDB Native向集合中插入记录
现在让我们尝试在集合中插入一个文档。我们在这里代表将一个股票代码添加到一个观察列表中。insertOne()函数被用来完成这项任务。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').insertOne({
ticker: 'AAPL',
inPortfolio: false
}, (err, result) => {
if (err) {
return console.log('Unable to insert stock', err);
}
console.log(JSON.stringify(result.ops, undefined, 2));
});
client.close();
});
我们可以再次运行这个文件并看到结果。由于我们得到的是一个新股票的实例,而不是一个错误--看起来一切都很顺利。
database $node mongodb-connect.js
Connected to MongoDB[ {
"ticker": "AAPL", "inPortfolio": false,
"_id": "5b55f32bbcbb001890cdb254"
}
]
我们还可以使用Mongo Compass来检查结果。

使用Compass查看新的文件,看起来也不错。
ObjectId
当我们在Mongo中插入一个新的文档时,注意我们得到的_id字段是我们结果的一部分。我们没有指定这个值,Mongo为我们创建了它。
"_id": "5b55f32bbcbb001890cdb254"
与大多数数据库系统一样,数据库中的任何数据都有一个唯一的标识符。在Mongo中,这就是ObjectId。ObjectId不是**一个自动递增的整数,就像你在基于SQL的系统中经常看到的那样。Mongo使用一个随机生成的ID。这样做的一个原因是,当一个大型系统扩展时,没有必要在插入一个新的文档之前首先检查最大的自动递增的id是什么。Mongo只是生成一个新的随机id,然后它就走了。ObjectId本身是一个12字节的值,前4字节是一个时间戳。这就是为什么没有像你在基于SQL的系统中看到的created_at字段。接下来的3个字节是一个机器标识符。然后是2个字节,代表进程ID。最后的3个字节是一个计数器。所有这些一起工作来创建这个随机值。如果你感到好奇,可以在文档中了解更多关于ObjectId的信息。
使用MongoDB Native获取数据
现在我们可以开始从Mongo获取一些数据了。我们可以在数据库目录中添加一个新文件。我们将其称为数据库--fetch.js。

我们在幕后向我们的数据库插入了一些股票,所以我们可以在这里演示find().toArray()函数。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').find().toArray().then((docs) => {
console.log('Stocks');
console.log(JSON.stringify(docs, undefined, 2));
}, (err) => {
console.log('Unable to fetch stocks', err);
});
client.close();
});
当我们运行database-fetch.js文件时,我们看到下面的结果数组。这是一个由三个对象组成的数组,每个对象都有一个独特的_id、ticker和inPortfolio属性。
database $node database-fetch.js
Connected to MongoDB
Stocks
[
{
"_id": "5b55f32bbcbb001890cdb254",
"ticker": "AAPL",
"inPortfolio": false
},
{
"_id": "5b55f90ed81f3928c0423f41",
"ticker": "MSFT",
"inPortfolio": true
},
{
"_id": "5b55f925330ad628406bcab3",
"ticker": "NFLX",
"inPortfolio": false
},
{
"_id": "5b55f9575e8bc54238453153",
"ticker": "MDB",
"inPortfolio": true
}
]
上述查询可能代表了一个观察列表中的所有股票。然而,也许我们只想看到那些在你的投资组合中的股票。你可能正在观察四只股票,但你实际上只为你的投资组合购买了两只。我们可以这样修改查询,使之更加细化。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').find({
inPortfolio: true
}).toArray().then((docs) => {
console.log('Stocks');
console.log(JSON.stringify(docs, undefined, 2));
}, (err) => {
console.log('Unable to fetch stocks', err);
});
client.close();
});
现在,当我们运行该文件时,我们可以看到该查询只返回inPortfolio属性被设置为 "true "的股票。所以看起来我们的投资组合中目前有微软和Mongodb Inc。
database $node database-fetch.js
Connected to MongoDB
Stocks
[
{
"_id": "5b55f90ed81f3928c0423f41",
"ticker": "MSFT",
"inPortfolio": true
},
{
"_id": "5b55f9575e8bc54238453153",
"ticker": "MDB",
"inPortfolio": true
}
]
计算集合中的文件
如果你想查询一个集合中的文件数量,你可以像下面这样做。在我们的例子中,这显示了我们观察清单上的所有股票,无论我们是否已经购买了它们。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').find().count().then((count) => {
console.log(`Stocks count: ${count}`);
}, (err) => {
console.log('Unable to fetch stocks', err);
});
client.close();
});
下面是该查询的输出。正如我们所期望的那样。
database $node database-fetch.js
Connected to MongoDB
Stocks count: 4
使用MongoDB Native删除文件
接着是删除功能,我们可以在数据库目录下创建一个名为mongodb-delete.js的新文件。

让我们想象一下,我们想简单地删除我们观察清单上的任何股票,这些股票不在我们的投资组合中。我们可以使用deleteMany()函数来做到这一点。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').deleteMany({
inPortfolio: false
}).then((result) => {
console.log(result);
});
client.close();
});
我们可以运行JavaScript文件,得到如下结果。实际上,有一大块输出被我们省略了,因为我们真正关心的是n=2,ok=1。这意味着有两个文件受到影响(被删除),而且结果还不错(成功了)。
database $node mongodb-delete.js
Connected to MongoDB
CommandResult {
result: { n: 2, ok: 1 }
这对我们来说意味着苹果和Netflix不再在我们的观察名单上了。现在我们只有微软和Mongo公司。
也许我们想卖掉微软的股票,把它从我们的观察列表和投资组合中删除。我们可以用deleteOne()来做到这一点。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').deleteOne({
ticker: 'MSFT'
}).then((result) => {
console.log(result);
});
client.close();
});
运行该文件显示,1个文件被删除了,一切都很顺利。
database $node mongodb-delete.js
Connected to MongoDB
CommandResult {
result: { n: 1, ok: 1 }
让我们用Compass看看我们现在在数据库中的情况。看起来MDB股票是我们拥有的最后一只股票。

原来我们需要获得一些资金,所以我们需要卖掉MDB,以便拿回我们的资金。这一次我们将像这样使用findOneAndDelete()。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').findOneAndDelete({
ticker: 'MDB'
}).then((result) => {
console.log(result);
});
client.close();
});
当我们运行该程序时,我们看到MDB被删除了,现在我们的观察列表或投资组合中没有股票。
database $node mongodb-delete.js
Connected to MongoDB
{ lastErrorObject: { n: 1 },
value:
{ _id: 5b55f9575e8bc54238453153,
ticker: 'MDB',
inPortfolio: true },
ok: 1 }
使用MongoDB Native更新文档
最后,我们可以看看如何在MongoDB中更新文档。然而,你可能会看到一个问题。我们的观察列表或投资组合中已经没有股票了。让我们使用insertMany()一次性添加一堆。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').insertMany([{
ticker: 'MDB',
inPortfolio: true
}, {
ticker: 'NFLX',
inPortfolio: true
}, {
ticker: 'AAPL',
inPortfolio: true
}, {
ticker: 'MSFT',
inPortfolio: true
}, {
ticker: 'IQ',
inPortfolio: true
}]).then((result) => {
console.log(result);
});
client.close();
});
很好,所有这些股票都回到了观察列表和投资组合中。现在我们要更新投资组合。让我们在项目中添加一个新的文件,名为mongodb-update.js。

在这一节中,我们将使用的函数是findOneAndUpdate()。在这种情况下,我们想把微软从我们的投资组合中删除,但把它保留在我们的观察列表中。因此,这意味着我们需要找到MSFT,并将它的inPortfolio属性设置为false。
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/StockApp', {
useNewUrlParser: true
}, (err, client) => {
if (err) {
return console.log('Unable to connect to MongoDB');
}
console.log('Connected to MongoDB');
const db = client.db('StockApp');
db.collection('Stocks').findOneAndUpdate({
ticker: 'MSFT'
}, {
$set: {
inPortfolio: false
}
}, {
returnOriginal: false
}).then((result) => {
console.log(result);
});
client.close();
});
运行mongodb-update.js文件,我们得到了这个响应。
database $node mongodb-update.js
Connected to MongoDB
{ lastErrorObject: { n: 1, updatedExisting: true },
value:
{ _id: 5b561c1c480b624574e1c6a2,
ticker: 'MSFT',
inPortfolio: false },
ok: 1 }
这看起来像是做了手脚。让我们也在Compass中检查一下。

Node MongoDB本地总结
我们在Node.js中使用MongoDBNative的教程就到此为止了。很多时候,我们会使用像Mongoose这样的专用ORM来完成这类工作,但正如我们在本教程中所看到的--它也可以用MongoDB Native来完成,而且同样有效。