8

I have website configuration (currently stored as JSON file), and I would like to move it to MongoDB and probably use Mongoose to handle read-write operations and perform validation through schemas.

Configuration is an object with limited amount of keys, similar to that:

{
  siteOffline: false,
  storeOffline: false,
  priceMultipliers: {
    a1: 0.96
    a2: 0.85
  },
  ...
}

Should it be made a collection with key-value entries? Not sure how to enforce Mongoose schema in this case.

Should it be made a collection with a single document? Not sure how to guarantee that there is only one document at a time.

Any other options?

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • So you only need to store 1 document at a time? I'm not sure you need a database for that. Mongo schemas are used for storing multiple instances of the same data structure (AKA structured data) – nadavvadan Nov 30 '16 at 07:54
  • Yes, one at a time. I'm ok with static JSON file for read-only access, but since the config should be modified in realtime from backend and Mongoose is already used, I would like to use it for validation, and concurrent access, and caching plugin, and so on. – Estus Flask Nov 30 '16 at 08:00

2 Answers2

7

Ok, one thing at a time :

if you want to use mongoose, you should have your full config as one document :

var siteConfig = new Schema({
  siteOffline: Boolean,
  storeOffline: Boolean,
  priceMultipliers: {
    a1: Number
    a2: Number
  } 
});

Then, if you want a one document only collection, you can use MongoDB capped collections

I suggest you go through the multiple options that Mongoose allows, here

The Schema for your one-doc collection would be something like :

   var config = new Schema({
      siteOffline: Boolean,
      storeOffline: Boolean,
      priceMultipliers: {
        a1: Number
        a2: Number
      } 
    }, { 
      collection:'config',
      capped: { size: 1024, max: 1} 
    });

There's some irony in having a "collection" of only one document though :)

Another "hack" solution that could work better for you is to use a secured field (of which you cannot change the value), and add a unique index on that field. Read this for more info The field could be present in the document but not in the model (virtual). Again, this is hacky, but your use case is a bit strange anyway :)

Community
  • 1
  • 1
xShirase
  • 11,975
  • 4
  • 53
  • 85
  • Capped collection looks like a neat trick. However, the thing that worries me is updating the document. Generally it would be nice to do something like 'find one and upsert', while it looks like capped collection is restricted to inserts. – Estus Flask Nov 30 '16 at 08:17
  • It's neat but definitely very hacky. I'll try to offer alternatives. – xShirase Nov 30 '16 at 08:21
  • Thanks, I've ended up with unique field that had default value and it was the only allowed value for the field. But capped approach would work too. – Estus Flask Dec 03 '16 at 20:21
4

The capped approach works but it doesn't allow updating fields. There is a better solution using the immutable field property (>= mongoose v5.6).

In addition, you can add the collection option to your schema to prevent mongoose from pluralize the name of the collection

let configSchema = new Schema(
    {
        _immutable: {
            type: Boolean,
            default: true,
            required: true,
            unique : true,
            immutable: true,
        },

        siteOffline: Boolean,
        storeOffline: Boolean,
        priceMultipliers: {
            a1: Number
            a2: Number
        },
    },
    {
        collection:'config',
    }
);

var Config = mongoose.model( 'config', configSchema );
Config.updateOne( {}, { siteOffline: false });

I hope it will help

Raphael Deiana
  • 750
  • 4
  • 20
  • Thanks, this looks promising. I didn't use immutable fields yet. `_immutable` is random internal name that imposes a restriction, isn't it? Can you add to the answer how it's supposed to be updated? – Estus Flask Mar 21 '20 at 19:43
  • 1
    I just updated the answer. There is nothing special to do when updating it. You can replace "_immutable" by any other fieldname. – Raphael Deiana Mar 21 '20 at 20:13