Nodejs想用MongoDB来保存书籍,该如何设计数据库比较好?

Nodejs想用MongoDB来保存书籍,该如何设计数据库比较好?

想用MongoDB来保存书籍,而书的格式刚好是树形结构的,该如何去设计数据库比较好呢? 在查找父节点查找子节点方面都是比较快的。 或者大多数是通过父节点找到子节点, 而很少通过子节点找到父节点。

8 回复

Node.js 使用 MongoDB 保存书籍的设计方案

在 Node.js 中使用 MongoDB 存储具有树形结构的书籍数据时,我们可以利用 MongoDB 的嵌套文档特性以及引用(references)来实现高效的查询操作。由于大多数情况下是通过父节点查找子节点,我们可以考虑以下设计方案。

数据库设计

  1. 书籍集合(Books Collection):
    • 每本书都有一个唯一的 _id
    • 每本书可以有一个 parentId 字段来表示其父节点。
    • 每本书还可以有其他字段,如 title, author, publishedDate 等。
{
  "_id": ObjectId("..."),
  "title": "Node.js in Action",
  "author": "Manuel Kiessling",
  "publishedDate": "2014-03-25",
  "parentId": ObjectId("..."), // 可以为空,表示这是根节点
  ...
}
  1. 索引设计:
    • parentId 上创建索引,以便快速查找子节点。
    • _id 上创建唯一索引,确保每个文档的唯一性。
db.books.createIndex({ "parentId": 1 });
db.books.createIndex({ "_id": 1 }, { unique: true });

示例代码

以下是一个简单的示例代码,展示如何使用 Mongoose 来定义模型并进行基本的 CRUD 操作:

const mongoose = require('mongoose');

// 定义书籍模型
const bookSchema = new mongoose.Schema({
  title: String,
  author: String,
  publishedDate: Date,
  parentId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Book'
  }
});

const Book = mongoose.model('Book', bookSchema);

// 插入新书
async function addBook(bookData) {
  const newBook = new Book(bookData);
  await newBook.save();
}

// 查找所有子节点
async function findChildren(parentId) {
  return await Book.find({ parentId });
}

// 查找所有父节点
async function findParents(childId) {
  return await Book.findOne({ _id: childId }).populate('parentId');
}

// 示例使用
(async () => {
  await mongoose.connect('mongodb://localhost:27017/bookstore', { useNewUrlParser: true, useUnifiedTopology: true });

  // 添加一些书籍
  await addBook({ title: 'Node.js in Action', author: 'Manuel Kiessling', publishedDate: new Date('2014-03-25') });
  await addBook({ title: 'Express in Action', author: 'David Gonzalez', publishedDate: new Date('2018-09-25'), parentId: ObjectId('...') });

  // 查找所有子节点
  const children = await findChildren(ObjectId('...'));
  console.log(children);

  // 查找所有父节点
  const parent = await findParents(ObjectId('...'));
  console.log(parent);

  mongoose.disconnect();
})();

总结

通过这种方式,我们可以在 MongoDB 中高效地存储和查询树形结构的书籍数据。利用 parentId 字段和索引,可以轻松实现对子节点的快速查找。同时,Mongoose 提供了方便的 API 来处理这些操作。


并不感觉 mongo 在这方面有什么优势啊。为什么用 mongo 呢?

…不应该写静态TXT路由么233333。

就直接树形结构啊,一个doc一本书,再加一些冗余数据来优化查询

这个问题前段时间遇到过,不过我用的都是关系型数据库,没有用mongo,因为我不会,, 而且我们的书籍一般是存入到数据库中,都不会再修正书籍的内容了,然后取的时候一般是按照章节来取数据, 当时想到的方法主要有两个: 1、主要是在每个章节记录父节点的值 这个写的时候要还原一棵树逻辑比较复杂,查询和插入的时候记录的数据也比较多 2、使用nested set model来存储, 这个感觉完全满足我的要求,可以快速的还原一棵树,而且插入的时候不用纠结于父节点到底是谁, 参考:http://en.wikipedia.org/wiki/Nested_set_model

ps:看mongodb的官方网站,存储树的格式,貌似跟表没多大差别么,求指导,表示对于mongo不懂 http://docs.mongodb.org/manual/applications/data-models-tree-structures/

官方给举了四种树的例子,看哪种合适你。 用起来总是有那么点不爽。

不过弱弱的说一下,关系数据库用起也好不到哪去。

要使用MongoDB保存树形结构的书籍数据,并且主要的操作是查找父节点和子节点,可以考虑使用嵌套文档(嵌套结构)或引用文档(使用引用)。下面是两种设计方法的示例:

方法一:嵌套文档

在这种方法中,将所有子节点直接嵌入到父节点中。

{
    "_id": ObjectId("650c3f9e4b91d73c9f2f258c"),
    "name": "书籍分类",
    "children": [
        {
            "_id": ObjectId("650c3f9e4b91d73c9f2f258d"),
            "name": "子分类A",
            "children": [
                {
                    "_id": ObjectId("650c3f9e4b91d73c9f2f258e"),
                    "name": "子分类A-1"
                }
            ]
        },
        {
            "_id": ObjectId("650c3f9e4b91d73c9f2f258f"),
            "name": "子分类B"
        }
    ]
}

示例代码

const mongoose = require('mongoose');

const bookSchema = new mongoose.Schema({
    name: String,
    children: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Book' }]
});

const Book = mongoose.model('Book', bookSchema);

// 插入数据
async function addBook() {
    const rootBook = new Book({ name: '书籍分类' });
    await rootBook.save();

    const subCategoryA = new Book({ name: '子分类A' });
    const subCategoryA1 = new Book({ name: '子分类A-1' });

    subCategoryA.children.push(subCategoryA1._id);
    await subCategoryA.save();

    rootBook.children.push(subCategoryA._id);
    await rootBook.save();
}

addBook();

方法二:引用文档

在这种方法中,每个父节点只包含其子节点的引用。

{
    "_id": ObjectId("650c3f9e4b91d73c9f2f258c"),
    "name": "书籍分类",
    "children": [ObjectId("650c3f9e4b91d73c9f2f258d")]
}

示例代码

const mongoose = require('mongoose');

const bookSchema = new mongoose.Schema({
    name: String,
    children: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Book' }]
});

const Book = mongoose.model('Book', bookSchema);

// 插入数据
async function addBook() {
    const rootBook = new Book({ name: '书籍分类' });
    await rootBook.save();

    const subCategoryA = new Book({ name: '子分类A' });
    const subCategoryA1 = new Book({ name: '子分类A-1' });

    subCategoryA.children.push(subCategoryA1._id);
    await subCategoryA.save();

    rootBook.children.push(subCategoryA._id);
    await rootBook.save();
}

addBook();

这两种方法都可以满足需求,但嵌套文档更方便地进行树形遍历,而引用文档则更适合大数据量的情况。根据具体场景选择合适的方法。

回到顶部