TomGrill Games TomGrill Games - 3 months ago 19
Android Question

Firebase multi-location rules - same value

This is what I want at the end:

{
"data" : {
"account" : {
"K1472290187836" : {
"created" : 1472290190043,
"id" : "K1472290187836"
}
},
"auth" : {
"d182ddec-f1c7-41c5-8b0e-198bfb5d9efe" : {
"account_id" : "K1472290187836",
"active" : true,
"created" : 1472290190043,
"id" : "d182ddec-f1c7-41c5-8b0e-198bfb5d9efe"
}
}
}
}


This are my classes for the data:

public class Account {
public long created;
public String id;

public HashMap<String, Object> toMap() {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", id);
map.put("created", ServerValue.TIMESTAMP);
return map;
}
}

public class Auth {
public String id;
public long created;
public boolean active;
public String account_id;

public HashMap<String, Object> toMap() {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", id);
map.put("created", ServerValue.TIMESTAMP);
map.put("active", active);
map.put("account_id", account_id);
return map;
}
}


This is my multi-location update:

final Auth auth = new Auth();
auth.id = FirebaseAuth().getCurrentUser().getUid();
auth.active = true;
auth.account_id = "K" + System.currentTimeMillis(); // TODO replace with proper id generator

final Account account = new Account();
account.id = auth.account_id;

HashMap<String, Object> newUserMap = new HashMap<String, Object>();
newUserMap.put("/data/account/" + account.id, account.toMap());
newUserMap.put("/data/auth/" + auth.id, auth.toMap());


FirebaseDatabase().getReference().updateChildren(newUserMap);


What I need are the rules which validate that data/account/$account_id/id has the same value as /data/auth/$auth_id/account_id before data can be stored.

Answer

Trimming the data back to the minimum, it seems like you want:

{
  "data" : {
    "account" : {
      "K1472290187836" : {
        "id" : "K1472290187836"
      }
    },
    "auth" : {
      "d182ddec-f1c7-41c5-8b0e-198bfb5d9efe" : {
        "account_id" : "K1472290187836",
      }
    }
  }
}

This is probably a good start:

{
  "rules": {
    "data": {
      "account": {
        "$id": {
          "id": {
            ".validate": "newData.val() == $id"
          }
        }
      },
      "auth": {
        "$uid": {
          ".write": "$uid === auth.uid",
          "account_id": {
            ".validate": "
newData.parent().parent().child('account').child(newData.val()).exists() &&
newData.parent().parent().child('account').child(newData.val()).child('id').val() === newData.val()"
          }
        }
      }
    }
  }
}

You don't really need the double condition on the account_id validation, since the second one duplicates the functionality of the first. But since I wasn't sure whether you want to validate the account key or the value of the id property, I added both conditions for easy copy/paste/remove-the-one-you-don't-care-about.

I recommend reconsidering if you really need to store the ID twice in that fragment. Data duplication is common, but in this case I don't see a lot of value gain (and it leads to considerations like the one above: which is leading?).