[英]MongoDB get the number of documents (count) in a collection using Node.js
[英]Get mongodb collection by name in node.js
我目前正在學習 node.js,這是我的第一個項目。 它(據說)是一個簡單的待辦事項列表應用程序,其中有多個我可以加載/編輯/保存/刪除的列表。
在 todo_list.ejs 文件中,我有一個 div,其中列出了所有集合名稱:
<div id="list_container" class="lists">
<ul id="col_list" class="collection-list">
<% lists.forEach(list => { %>
<li class="collection-list-item">
<div class="list-name-container">
<a href="/<%=list.name %>" class="list-link">
<span class="list-name" name="list_name"><%=list.name %></span>
</a>
</div>
</li>
<% }) %>
</ul>
</div>
當我單擊列表的鏈接時。 我嘗試使用以下代碼加載一個新列表(這是一個 mongodb 集合):
app.route("/:list_name").get((req, res) => {
MongoClient.connect(process.env.DB_CONNECT, (err, db) => {
if(err) throw err;
var database = db.db("myFirstDatabase");
const cursor = database.collection(req.params.list_name).find({}); /* stuck here */
database.listCollections().toArray((err, collections) => {
if(err) throw err;
db.close();
collections.forEach(element => {
if(element.name == req.params.list_name){
current_list = element;
current_list_name = element.name;
}
});
task.find({}, (err, todo_tasks) => { /*currently using the model.find() method to list all the documents which always looks at the "tasks" collection*/
res.render("todo_list.ejs", { tasks: todo_tasks, lists: collections, curr_list: current_list_name });
});
});
});
});
我評論了我卡在上面的代碼中的地方。 我正在嘗試按名稱獲取 mongodb 集合,然后將其所有內容加載到列表中,但我不知道如何按名稱查找集合。 通讀 node.js 文檔將我帶到 cursor object,其中包含大量信息和屬性,我不知道如何處理...
有沒有一種簡單的方法可以按名稱查找集合並獲取其文檔列表?
編輯1:
這是我添加任務的地方:
//ADD TASK TO LIST
app.post('/', async (req, res) => {
const tsk = new task({ /*the mongodb model for tasks*/
content: req.body.content,
deadline: req.body.deadline
});
try {
await tsk.save();
res.redirect("/");
} catch(e) {
console.log(e);
res.redirect("/");
}
});
我不會在這個答案中解決EJS
部分,因為我沒有資格並且您提供的代碼似乎都很好。 但是,我將回顧后端部分。
此外,由於我不知道您有什么樣的編碼背景(如果有的話),這個答案將包含很多關於可能簡單概念的解釋。
從您的第二個代碼片段中,有幾件事要討論:
根據 OP 的知識,還有很多內容需要涵蓋,例如try/catch
子句、MongoDB 模型驗證、express Router
的使用等等,但我只會在需要時編輯我的答案。
對於答案的 rest,大部分代碼都會被async/await
關鍵字包圍。 這些是代碼正常工作所必需的。
基本上,JS 是為 web 設計的語言,您有時需要等待網絡或數據庫請求完成,然后再執行任何其他操作。 這就是callbacks
、 promises
或async/await
語法(這是 promise 的語法糖)派上用場的地方。
假設您需要像您的示例一樣檢索任務列表:
app.route("/:list_name").get((req, res) => {
MongoClient.connect(process.env.DB_CONNECT, (err, db) => {
if(err) throw err;
var database = db.db("myFirstDatabase");
const cursor = database.collection(req.params.list_name).find({}); /* stuck here */
console.log(cursor);
// ..........
});
});
JS 默認是異步的,如果你運行這段代碼, cursor
可能是undefined 。 原因是代碼不會等待database.collection(.............
完成以繼續執行。但是在上述callback/promises/async-await
的幫助下callback/promises/async-await
,我們的代碼現在可以等待這條指令完成。
您可以在此處和此處閱讀 async/await ,並在此處查看 MongoDB 示例也在使用 async/await,但您將在以下部分中看到它的更多“實際”用法。
請記住,您正在使用什么(無論是回調、承諾還是異步/等待語法)完全取決於您和您的偏好。
由於當前編寫的代碼,每次用戶單擊列表中的任何項目時,都會建立到 MongoDB 的連接,並且該連接不屬於路由處理程序。 您的后端應用程序應該連接到數據庫一次(至少在這種情況下,對於某些高級情況,啟動多個連接可能很有用),並在您的后端應用程序停止時關閉連接(通常不是這種情況) API)。
例如, Atlas
雲數據庫的連接數限制為 500。 這意味着如果 501 個用戶同時點擊您前端列表中的一個項目,最好的情況是有人沒有得到他所要求的內容,但情況可能更糟。
對於這個問題,你有幾個選擇。 一種是使用 go 的框架,該框架可幫助您利用一些代碼和樣板,例如Mongoose或使用本機 MongoDB 驅動程序,我堅信我們會這樣做,因為您似乎已經使用最低layer first 將使您更快地學習更高級別的框架。
現在,讓我們解決這個問題。 我們希望將數據庫連接放在其他會被調用一次的地方。 同樣,您可以使用幾個選項 go ,但我喜歡為它創建一個 class ,並導出一個新實例以在我的代碼中的任何位置執行我想要的操作。 這是一個(非常)簡單的示例,說明了我的最小選擇:
mongo-client.js:
import { MongoClient } from 'mongodb';
class MongoCli {
constructor() {
let url = `mongodb://testuser:my_sup3r_passwOrd@127.0.0.1:27017/?authSource=my_database_name`;
this.client = new MongoClient(url, { useUnifiedTopology: true });
}
async init() {
if (this.client) {
await this.client.connect();
this.db = this.client.db('test');
} else
console.warn("Client is not initialized properly");
}
}
export default new MongoCli();
當然,他自己的這段代碼是行不通的,我們需要在定義路由之前調用並等待它。 所以,就在app.route("/:list_name")............
之前,調用這個: await MongoCli.init();
.
這是我的(再次,真的)簡單的server.js
的樣子(我已將 mongo-client 代碼與服務器分開):
import express from 'express';
import MongoCli from './mongo-cli.js';
const server = async () => {
const app = express();
await MongoCli.init();
app.route("/:list_name").get(async (req, res) => {
});
return app;
};
export default server;
現在,讓我們從頭開始實現你真正想要的東西,也就是一旦用戶點擊任務主題,它將顯示他點擊的主題的所有任務:
import express from 'express';
import MongoCli from './mongo-cli.js';
const server = async () => {
const app = express();
await MongoCli.init();
app.route("/:list_name").get(async (req, res) => {
// we will query the collection specified by req.params.list_name
// then, .find({}) indicates we want all the results (empty filter)
// finally, we call .toArray() to transform a Cursor to a human-readable array
const tasks = await MongoCli.db.collection(req.params.list_name).find({}).toArray();
// making sure we got what we needed, you can remove the line below
console.log(tasks);
// return a HTTP 200 status code, along with the results we just queried
res.status(200).json(tasks);
});
return app;
};
export default server;
很簡單,對吧? 請記住,我的server.js
可能看起來不像你的,因為有很多方法可以處理這個問題,開發人員可以找到自己喜歡的方法,但你明白了。
我們得到了 GET 路由,當我們調用路由時我們得到了結果,一切都很好。 ... 不完全的。
如果我們有 1500 個任務主題,現在會發生什么? 我們真的應該創建 1500 個不同的 collections,知道任務由描述、狀態,最終是名稱組成嗎? 當然,我們可以做到,但這並不意味着我們必須這樣做。
相反,如何創建一個且唯一的收集tasks
,並為其添加一個關鍵topic
?
考慮到上面的句子,現在的路線如下所示:
import express from 'express';
import MongoCli from './mongo-cli.js';
const server = async () => {
const app = express();
await MongoCli.init();
app.route("/:topic_wanted").get(async (req, res) => {
// we now know the collection is named 'tasks'
// then, .find({topic: req.params.topic_wanted}) indicates we want all the results where the key 'topic' corresponds to req.params.topic_wanted
// finally, we call .toArray() to transform a Cursor to a human-readable array
const tasks = await MongoCli.db.collection('tasks').find({topic: req.params.topic_wanted}).toArray();
// making sure we got what we needed
console.log(tasks);
// return a HTTP 200 OK, along with the results we just queried
res.status(200).json(tasks);
});
return app;
};
export default server;
我希望我不是太離題,我的回答可以幫助你。 另外,我在寫答案時看到您現在需要弄清楚如何發布任務。 如果您需要更多信息/解釋甚至發布任務的幫助,請在評論中告訴我。
connect
回調 function 更改為async
。database.collection(req.params.list_name).find({});
的末尾添加toArray()
function;await
。 您可以選擇.then
或async/await
,這取決於您!
app.route("/:list_name").get((req, res) => {
MongoClient.connect(process.env.DB_CONNECT,async (err, db) => {
if(err) throw err;
var database = db.db("myFirstDatabase");
const todo_tasks = await database.collection(req.params.list_name).find({}).toArray(); /* add '.toArray()' */
database.listCollections().toArray((err, collections) => {
if(err) throw err;
db.close();
collections.forEach(element => {
if(element.name == req.params.list_name){
current_list = element;
current_list_name = element.name;
}
});
res.render("todo_list.ejs", { tasks: todo_tasks, lists: collections, curr_list: current_list_name });
});
});
});
app.route("/:list_name").get((req, res) => {
// Connecting to MongoDb database
MongoClient.connect(process.env.DB_CONNECT, async (err, db) => {
if (err) throw err;
// Choosing 'myFirstDatabase' database
const database = db.db("myFirstDatabase");
let todo_tasks = [];
let collections = [];
let current_list_name = "";
// Getting selected list items(todo tasks) to array
try {
todo_tasks = await database.collection(req.params.list_name).find({}).toArray(); // Change :- Add '.toArray()'
} catch (err) {
if (err) throw err;
}
// Getting collections names
try {
collections = await database.listCollections().toArray();
db.close();
} catch (err) {
if (err) throw err;
}
// Getting selected list details
collections.forEach(element => {
if (element.name === req.params.list_name) {
current_list = element; // I don't understand what this code here
current_list_name = element.name;
}
});
// Rendering front end
res.render("todo_list.ejs", {
tasks: todo_tasks,
lists: collections,
curr_list: current_list_name,
});
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.