Eric Kim
Eric Kim

Reputation: 1

Firebase data cap on children

Is there any way to set a data cap on Firebase children?

E.g.,...

{
    Customer1: {},
    Customer2: {},
    Customer3: {}
}

For my particular example, depending on a customer's payment model will dictate how much space they are allowed to use. Say for Customer1 and Customer2, I only want at most 25MB of space used. Any new data will either remove older data or not get appended at all.

Should I do something where for a certain Customer, I check the sizeof of the the WHOLE data set and prevent customers from adding in new data if it exceeds a certain amount?

It doesn't seem like an ideal solution to be honest...

Upvotes: 0

Views: 140

Answers (2)

André Kool
André Kool

Reputation: 4978

After some trial and error i found out it is actually possible to have a cap on data within the firebase security rules. But only to a certain extend!

The limiting factor is that you can only check the value of a primitive type (string, number or bool). When a node has children you would have to check the value of each of that children, this implies you know what data you can expect.

Below is an example of the security rules needed to accomplish this. The rules are only for a primitive type or a node with a maximum of 3 (specified) primitive children.

"rules": {
  ".read": true,
  ".write": true,
  "$key":{
    //validate that the data has no children
    ".validate":"(!newData.hasChildren() && 
    //and validate if it is a string within a certain length
    (newData.isString() && newData.val().length < 10) || 
    //or validate if it is a number within a certain range
    (newData.isNumber() && (newData.val() < 10 && newData.val() > -10)) || 
    //or validate if it is a bool
    newData.isBoolean()) || 
    //Or rince and repeat for all possible child nodes
    newData.hasChildren()",
    "childA":{
      ".validate":"(!newData.hasChildren() && 
      (newData.isString() && newData.val().length < 10) || 
      (newData.isNumber() && (newData.val() < 10 && newData.val() > -10)) || 
      newData.isBoolean())"
    },
    "childB":{
      ".validate":"(!newData.hasChildren() && 
      (newData.isString() && newData.val().length < 10) || 
      (newData.isNumber() && (newData.val() < 10 && newData.val() > -10)) || 
      newData.isBoolean())"
    },
    "childC":{
      ".validate":"(!newData.hasChildren() && 
      (newData.isString() && newData.val().length < 10) || 
      (newData.isNumber() && (newData.val() < 10 && newData.val() > -10)) || 
      newData.isBoolean())"
    },
    //dismiss all child nodes you don't want
    "$other": {".validate": false}
  }
}

Some of the downsides about this sollution are:

  1. You have to know what data you can expect (and update your rules each time this changes)
  2. The rules will get exponentially larger the more child nodes you can have
  3. You can't really have a "total" cap on a node but only on the primitives that make up a node. For example (childA + childB + childC) is smaller then X is not possible.
  4. You can't have a dynamic cap. But you could say locationFree has a cap of 10 and locationPremium has a cap of 100. But unfortunatly this would double the amount of rules needed and users will have different write locations depending on their cap.

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 599686

This is one of those requirements that you can't implement in the client-side application as the users will be able to bypass them if you do.

Instead you should implement this server-side, which leaves:

  • implement it in security rules
  • implement it in server-side code

There is no operator built-in Firebase Security Rules that gives the size of a node. You can determine the length of a string, but that's a bit little to go on.

So your best bet is to use server-side process, which is: a process that you control, which doesn't run on the client's device. With that server-side process you can calculate the node size in any way you see fit.

The process then writes the node size back into Firebase into a secured location (that only the process can write). The security rules can then check against this location and reject writes if the node is larger than the quota.

Upvotes: 0

Related Questions