簡體   English   中英

在 node.js 中按名稱獲取 mongodb 集合

[英]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部分,因為我沒有資格並且您提供的代碼似乎都很好。 但是,我將回顧后端部分。

此外,由於我不知道您有什么樣的編碼背景(如果有的話),這個答案將包含很多關於可能簡單概念的解釋。

概括

從您的第二個代碼片段中,有幾件事要討論:

  1. 異步代碼
  2. 數據庫連接和一般性
  3. 實際執行
  4. 代碼構想

根據 OP 的知識,還有很多內容需要涵蓋,例如try/catch子句、MongoDB 模型驗證、express Router的使用等等,但我只會在需要時編輯我的答案。

異步代碼

對於答案的 rest,大部分代碼都會被async/await關鍵字包圍。 這些是代碼正常工作所必需的。

基本上,JS 是為 web 設計的語言,您有時需要等待網絡或數據庫請求完成,然后再執行任何其他操作。 這就是callbackspromisesasync/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;

最后的話

我希望我不是太離題,我的回答可以幫助你。 另外,我在寫答案時看到您現在需要弄清楚如何發布任務。 如果您需要更多信息/解釋甚至發布任務的幫助,請在評論中告訴我。

試試這個,這應該可以。

我所做的更改:-

  1. MongoDb connect回調 function 更改為async
  2. database.collection(req.params.list_name).find({});的末尾添加toArray() function;
  3. 並使上述 function await

您可以選擇.thenasync/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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM