2

I have a personal project about writing articles. I do in nosql with mongoose. For my API i use nodejs + express. But i'm fluent with sql, but i'm begginer in Nosql...

My problem is about my articles with categories.

I want set 2 level of categories like that :

Category 1

  • Subcategorie 1
    • Article
  • SubCategorie 2
    • Article
  • SubCategorie 3
    • Article

Category 2

  • Subcategorie 4
    • Article
  • SubCategorie 5
    • Article
  • SubCategorie 6
    • Article

Then my articles are populate in subCategories.

I started to set 3 documents :

  • Categorie
  • SubCategorie
  • Articles

Like this way, i can populate my articles in SubCategorie, and populate my SubCategorie in Categorie.

But i'm not sure than is the best way to use mongoose and nosql in general. I need an other point of view.

I want respect the best practices obviously.

To be simple i'll need to :

  • Display all articles from SubCategory
  • Display all articles from Category
  • Display Category and SubCategory on the page of one article.

I would permit to use only the existent category as well.

Any suggestion ?

Thanks a lot ;)

Kiloumap Mrz
  • 2,133
  • 1
  • 9
  • 18
  • I think the three collections you suggested are a good start. For now it covers your requirements and provides enough flexibility. Just implement it, it's easy to change a mongodb model when new requirements do not fit your model. – Andre Paap Jun 01 '18 at 13:22

3 Answers3

2

As a general rule for document oriented databases, you should structure your documents according to the access.

If you want to have a page that renders a full article with the names of the category and subcategory, you could structure articles like that:

{
    "_id": ObjectId("5b0f9961076337823360d072"),
    "category": "Gadgets",
    "subcategory": "TVs",
    "title": "New TV from ACME",
    "text": "Lorem Ipsum ....",
    "published": ISODate("2018-05-31T06:42:41.270Z")
}

This way you can fetch all data for the article page with on query.

If you wanted to show all articles for one category and subcategory, you could filter on those fields and need only one query. In that case you should create indices on those fields to speed up the queries.

You could (but it depends on how you want to access your categories) save your categories and subcategories in one collection. Those documents could be structured like that:

{
    "_id": ObjectId("5b0f9961076337823360d072"),
    "name": "Gadgets",
    "subcategories": ["TVs", "Computers", "Phones"]
}

But perhaps that structure does not fit your needs. In that case you could have two collections. It always depends on the implementation of your application.

You will notice, that there are redundancies in the data structure. The name of the categories are saved multiple articles. But that is ok. You have to make sure in your application that the saved data is correct by validating the input before saving.

The redundancies prove another problem: If you want to rename a cateogry, you would have to update each document that has the category with the changed name. But those updates usually happen not often. Document design is a tradeoff. Fast fetching, because you only access one collection or even only one document. Tedious and slow updates. But with a good document structure you can minimize the slow operations and maximize the fast ones.

mbuechmann
  • 5,413
  • 5
  • 27
  • 40
  • To be simple i'll need to : - Display all articles from SubCategory - Display all articles from Category - Display Category and SubCategory on the page of one article. Your first solution could be nice, but that mean we could find all article from category, but have also some problem with same category with different spelling like TV, television, TVs... I would permit to use only the existent category. And in my api, i want check if category and sub category exists, then use it. I could find category in the article model btw... I don't know the best way .. :( – Kiloumap Mrz Jun 01 '18 at 13:48
  • Yes, misspellings do pose a problem. You have to make sure, that your data is saved correctly. In the case of category names, you could present the author with a select box. In addition you have to validate all values, before saving. I'll extend my answer. – mbuechmann Jun 01 '18 at 13:52
  • 1
    @KiloumapL'artélon lack of consistency is the main trade-off using document-oriented databases. This means your app should be able to handle these kind of mistakes: in your queries, using regular expressions; dictionaries of words to look for; case insensitive expressions... This may be counter-intuitive but noSQL basically throws off ACID properties in favor of (theoretically) more efficient queries and horizontal scaling. – Alexis Facques Jun 01 '18 at 14:00
1

As I've been taught personally, as opposed to relational, the main point of NoSQL is originally to avoid having to join tables with each other, as much as possible. This is typically a trade-off between data replication (ACID properties) and ease of update VS. query efficiency.

In practice, this would consist in nesting one document in the other. e.g, each Article would contain the Category data of which it belongs (but this could be implemented the other way around depending on your needs).

Article { name: string, content: string, category: Category { name: ... } }

The following is only my very personal opinion; but I'm not a huge fan of Mongoose in that matter. It does add up an abstraction layer which is indeed reassuring for developers coming from the relational world, but if not used with extreme care, you may easily fall back into doing relational with a tool not designed for that.

Edit: Much better example from mbuechmann above.

Alexis Facques
  • 1,783
  • 11
  • 19
-1

I think you can go with this approach. There will be 2 collections

  1. Article
  2. Categories

Categories collections will have for example following types documents.

{
    "_id" : ObjectId("5a7030519697334c17afe3e6"),
    "parent_id" : ObjectId("5a7030469697334c17afe3e5"),
    "name" : "cat 1",
    "is_subtype" : true,
    "sub_types" : [
        ObjectId("5a7030969697334c17afe3e9"),
        ObjectId("5a70309c9697334c17afe3ea")
    ],
}

Here you can now populate parent category and their child category by using their Id. Also In Article you can populate category information by category id.

And Article will have following types of documents

{
  "_id": ObjectId("5a7030519697334c17afe3e6"),
  "category_id": ObjectId("5a7030469697334c17afe3e5"),
  "text": "article 1",
  "slug": "article-1"
}

I hope this is what you're looking for.

parth
  • 624
  • 1
  • 10
  • 29
  • 1
    This totally looks like a relational database design. This won't make you leverage the advantages of a document based designs. To display an article plus the name of the category plus the name of the subcategory would take three queries. And those queries cannot be done in parallel, as you would have to fetch the article, read out the category-id, fetch the category and so on... – mbuechmann Jun 01 '18 at 14:10
  • You're wrong. You can get all three information within single query. Since we are using mongoose, we can populate categories from category table and also it's sub categories from category key of category collection. You don't need to write three different queries. And this is right declaration because if someone wants to display category list then you'll need separate unique id's for that. You can have same name if different sub categories so for that it'll require unique Id's to perform operations. – parth Jun 04 '18 at 04:37
  • This might be only one mongoose call, but it is not one query on the database level. It is not possible to query multiple collections with one call. – mbuechmann Jun 04 '18 at 06:03
  • If you're performing in query in Mongo DB then you are right. But that's where mongoose comes in. It allows you to populate multiple collections data within single query. If you are talking about application level programming then this way is correct. – parth Jun 04 '18 at 06:05
  • 1
    It seems to me that you are mixing up some concepts. `to query` means to send a request to the database. If you are calling a mongoose functions it is `a function call`. Although you only execute one mongoose function call, mongoose internally does multiple db queries. And that is inefficient, meaning sub-optimal document design. – mbuechmann Jun 04 '18 at 06:14