I have Two Dyna tress. Want to have drag and drop within the tree but not in between the tress.Please guide me how to disbale the drag and drop in between the tress.
$("#tree1")
.dynatree(
{
onActivate : function(node) {
alert("You activated " + node.data.title);
},
persist : true,
dnd : {
onDragStart : function(node) {
logMsg("tree.onDragStart(%o)", node);
return true;
},
onDragStop : function(node) {
logMsg("tree.onDragStop(%o)", node);
},
autoExpandMS : 1000,
preventVoidMoves : true,
onDragEnter : function(node, sourceNode) {
logMsg("tree.onDragEnter(%o, %o)", node,
sourceNode);
return true;
},
onDragOver : function(node, sourceNode, hitMode) {
logMsg("tree.onDragOver(%o, %o, %o)", node,
sourceNode, hitMode);
if (node.isDescendantOf(sourceNode)) {
return false;
}
if (!node.data.isFolder && hitMode === "over") {
return "after";
}
},
onDrop : function(node, sourceNode, hitMode, ui,
draggable) {
logMsg("tree.onDrop(%o, %o, %s)", node,
sourceNode, hitMode);
sourceNode.move(node, hitMode);
},
onDragLeave : function(node, sourceNode) {
logMsg("tree.onDragLeave(%o, %o)", node,
sourceNode);
}
},
children : [
{
title : "Public",
isFolder : true,
children : [ {
"title" : "Item 1"
}, {
"title" : "Folder 2",
"isFolder" : true,
"key" : "folder2",
"children" : [ {
"title" : "Sub-item 2.1",
"isFolder" : false
}, {
"title" : "Sub-item 2.2"
} ]
}, {
"title" : "Folder 3",
"isFolder" : true,
"key" : "folder3",
"children" : [ {
"title" : "Sub-item 3.1",
"isFolder" : false
}, {
"title" : "Sub-item 3.2",
"isFolder" : false
} ]
}, {
"title" : "Item 5"
} ]
} ]
});
and the Tree2 is
$("#tree2")
.dynatree(
{
onActivate : function(node) {
alert("You activated " + node.data.title);
},
persist : true,
dnd : {
onDragStart : function(node) {
logMsg("tree.onDragStart(%o)", node);
return true;
},
onDragStop : function(node) {
logMsg("tree.onDragStop(%o)", node);
},
autoExpandMS : 1000,
preventVoidMoves : true,
onDragEnter : function(node, sourceNode) {
logMsg("tree.onDragEnter(%o, %o)", node,
sourceNode);
return true;
},
onDragOver : function(node, sourceNode, hitMode) {
logMsg("tree.onDragOver(%o, %o, %o)", node,
sourceNode, hitMode);
if (node.isDescendantOf(sourceNode)) {
return false;
}
if (!node.data.isFolder && hitMode === "over") {
return "after";
}
},
onDrop : function(node, sourceNode, hitMode, ui,
draggable) {
logMsg("tree.onDrop(%o, %o, %s)", node,
sourceNode, hitMode);
sourceNode.move(node, hitMode);
},
onDragLeave : function(node, sourceNode) {
logMsg("tree.onDragLeave(%o, %o)", node,
sourceNode);
}
},
children : [
{
title : "Public",
isFolder : true,
children : [ {
"title" : "Item 1"
}, {
"title" : "Folder 2",
"isFolder" : true,
"key" : "folder2",
"children" : [ {
"title" : "Sub-item 2.1",
"isFolder" : false
}, {
"title" : "Sub-item 2.2"
} ]
}, {
"title" : "Folder 3",
"isFolder" : true,
"key" : "folder3",
"children" : [ {
"title" : "Sub-item 3.1",
"isFolder" : false
}, {
"title" : "Sub-item 3.2",
"isFolder" : false
} ]
}, {
"title" : "Item 5"
} ]
} ]
});
Please guide me on how should i achieve that Tree1 Nodes can be DnD with in me Tree1 and Trre2 Nodes can be DnD with in Tree2.
And restrict that Tree1 Nodes should not be dropped in Tree2 and vice versa.
You should use:
onDragEnter: function (targetNode, sourceNode) {
// Prevent dropping a node from a foreign tree
if (targetNode.tree !== sourceNode.tree) {
return false;
}
return true;
}
It checks if the tree of the node that you want to move (sourceNode) is the same tree as the tree of the node where you want to move (targetNode). If the two trees are not the same it prevents dropping.
Related
This is my json structure
{
"books" : {
"sample" : {
"eight" : {
"author" : "eighta",
"name" : "eight",
"sub" : {
"subauthor" : "eightauthor",
"subname" : "general"
}
},
"eleven" : {
"author" : "twelvea",
"name" : "twelve",
"sub" : {
"subauthor" : "elevenauthor",
"subname" : "general"
}
},
"five" : {
"author" : "fivea",
"name" : "five",
"sub" : {
"subauthor" : "fiveauthor",
"subname" : "fivesub"
}
},
"four" : {
"author" : "foura",
"name" : "four",
"sub" : {
"subauthor" : "fourauthor",
"subname" : "general"
}
},
"nine" : {
"author" : "ninea",
"name" : "nine",
"sub" : {
"subauthor" : "nineauthor",
"subname" : "ninesub"
}
},
"one" : {
"author" : "onea",
"name" : "one",
"sub" : {
"subauthor" : "oneauthor",
"subname" : "onesub"
}
},
"seven" : {
"author" : "seven",
"name" : "seven"
},
"six" : {
"author" : "sixa",
"name" : "six"
},
"ten" : {
"author" : "tena",
"name" : "ten"
},
"three" : {
"author" : "threea",
"name" : "three"
},
"two" : {
"author" : "twoa",
"name" : "two"
}
}
}
}
I want to fetch data which are having subname equal to general
My index rules
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".read": true,
".write": true,
"books": {
"$user_id": {
".indexOn": ["subname", "subauthor"]
}
}
}
}
}
https://myprojectpath/books/sample/eight.json?orderBy="subname"&equalTo="general"&print=pretty
Above rule is working fine. But I need to pass generic api to fetch the data where subname should be general. I cannot pass eight.json, nine.json, ten.json each time when I call. I should call only one api where it should provide the data where subname should be general.
If I understand you correctly you want to use a single query to search across all authors for their sub/subname property.
In that case you can define an index on books/sample for the sub/subname property of each child node:
"books": {
"sample": {
".indexOn": ["sub/subname", "sub/subauthor"]
}
}
The sample could be a $ variable here (such a $user_id), but the paths in .indexOn have to be known.
This creates an index under sample with the value of sub/subname for each child node, which you can then query with:
https://myprojectpath/books/sample.json?orderBy="sub/subname"&equalTo="general"&print=pretty
I've been trying to come up with a flat data structure for Firebase Database (as is recommended) and afterwards, a set of rules to control access correctly. My example is trying to demonstrate how you'd lock down/allow access to a db which is multi-tenanted across different organizations.
My first attempt was something like this:
Database structure: https://gist.github.com/peteski22/40b0a79a6854d7bb818919a5262f4a7e
{
"admins" : {
"8UnM6LIiZJYAHVdty6gzdD8oVI42" : true
},
"organizations": {
"-JiGh_31GA20JabpZBfc" : {
"name" : "Comp1 Ltd"
},
"-JiGh_31GA20JabpZBfd" : {
"name" : "company2 PLC"
}
},
"users" : {
"8UnM6LIiZJYAHVdty6gzdD8oVI42": {
"firstName" : "Peter",
"lastName" : "Piper",
"email" : "peter.piper#testtest.com",
"organization" : ""
},
"-JiGh_31GA20JabpZBfe" : {
"firstName" : "Joe",
"lastName" : "Blogs",
"email" : "joe.blogs#co1.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"WgnHjk5D8xbuYeA7VDM3ngKwCYV2" : {
"firstName" : "test",
"lastName" : "user",
"email" : "test.user#google.com",
"organization" : "-JiGh_31GA20JabpZBfd"
}
},
"employees" : {
"-JiGh_31GA20JabpZBeb" : {
"organization" : "-JiGh_31GA20JabpZBfc",
"firstName" : "Johnny",
"lastName" : "Baggs",
"email" : "j.baggss#co1.com",
"employeeNumber" : "ASV123456"
},
"-JiGh_31GA20JabpZBec" : {
"organization" : "-JiGh_31GA20JabpZBfc",
"firstName" : "Maheswari",
"lastName" : "Sanjal",
"email" : "mahe.sanjal#co1.com",
"employeeNumber" : "ASV111111"
},
"-JiGh_31GA20JabpZBce" : {
"organization" : "-JiGh_31GA20JabpZBfd",
"firstName" : "Fedde",
"lastName" : "le Grande",
"email" : "fedde.grande#co2.com",
"employeeNumber" : "ASV111111"
}
}
}
Database rules: https://gist.github.com/peteski22/b038d81641c1409cec734d187272eeba
{
"rules" : {
"admins" : {
".read" : "root.child('admins').hasChild(auth.uid)",
".write" : "root.child('admins').hasChild(auth.uid)"
},
"users" : {
"$user" : {
".read" : "data.child('organization').val() === root.child('users').child(auth.uid).child('organization').val()",
".write" : "root.child('admins').hasChild(auth.uid)"
}
},
"organizations" : {
"$organization" : {
".read" : "$organization === root.child('users').child(auth.uid).child('organization').val()",
".write" : "root.child('admins').hasChild(auth.uid)"
}
},
"employees" : {
"$employee" : {
".read" : "data.child('organization').val() === root.child('users').child(auth.uid).child('organization').val()",
".write" : "data.child('organization').val() === root.child('users').child(auth.uid).child('organization').val()"
}
}
}
}
However the problem here seemed to be that I couldn't do something like:
[GET] /employees
to see a collection of employees that belonged to the same organization as the logged in user.
After much faffing, I read this in the docs: https://firebase.google.com/docs/database/security/securing-data#rules_are_not_filters, which I think boils down to 'you're doing it wrong' if you want to get at the data the way I did.
Back to the drawing board, and after reading https://www.firebase.com/docs/web/guide/structuring-data.html / https://firebase.google.com/docs/database/web/structure-data
I made some changes to the db structure and rules:
Attempt #2 structure: https://gist.github.com/peteski22/4593733bf54815393a443dfcd0f34c04
{
"admins" : {
"8UnM6LIiZJYAHVdty6gzdD8oVI42" : true
},
"organizations": {
"-JiGh_31GA20JabpZBfc" : {
"name" : "Comp1 Ltd",
"users" : {
"-JiGh_31GA20JabpZBfe" : true,
"-JiGh_31GA20JabpZBff" : true,
"-JiGh_31GA20JabpZBea" : true
},
"employees" : {
"-JiGh_31GA20JabpZBeb" : true,
"-JiGh_31GA20JabpZBec" : true
}
},
"-JiGh_31GA20JabpZBfd" : {
"name" : "company2 PLC",
"users" :{
"WgnHjk5D8xbuYeA7VDM3ngKwCYV2" : true
},
"employees" :{
"-JiGh_31GA20JabpZBce" : true
}
}
},
"users" : {
"8UnM6LIiZJYAHVdty6gzdD8oVI42": {
"firstName" : "Peter",
"lastName" : "Piper",
"email" : "peter.piper#testtest.com",
"organization" : ""
},
"-JiGh_31GA20JabpZBfe" : {
"firstName" : "Joe",
"lastName" : "Blogs",
"email" : "joe.blogs#co1.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"-JiGh_31GA20JabpZBff" : {
"firstName" : "Sally",
"lastName" : "McSwashle",
"email" : "sally.mcswashle#co1.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"-JiGh_31GA20JabpZBea" : {
"firstName" : "Eva",
"lastName" : "Rushtock",
"email" : "eva.rushtock#payrollings.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"WgnHjk5D8xbuYeA7VDM3ngKwCYV2" : {
"firstName" : "test",
"lastName" : "user",
"email" : "test.user#google.com",
"organization" : "-JiGh_31GA20JabpZBfd"
}
},
"employees" : {
"-JiGh_31GA20JabpZBeb" : {
"organization" : "-JiGh_31GA20JabpZBfc",
"firstName" : "Johnny",
"lastName" : "Baggs",
"email" : "j.baggss#financeco.com",
"employeeNumber" : "ASV123456"
},
"-JiGh_31GA20JabpZBec" : {
"organization" : "-JiGh_31GA20JabpZBfc",
"firstName" : "Maheswari",
"lastName" : "Sanjal",
"email" : "mahe.sanjal#financeco.com",
"employeeNumber" : "ASV111111"
},
"-JiGh_31GA20JabpZBce" : {
"organization" : "-JiGh_31GA20JabpZBfd",
"firstName" : "Fedde",
"lastName" : "le Grande",
"email" : "fedde.grande#payrollings.com",
"employeeNumber" : "ASV111111"
}
}
}
Attempt #2 rules: https://gist.github.com/peteski22/e1be434cd1ea8ec2e630bec6d8aa714f
{
"rules" : {
"admins" : {
".read" : "root.child('admins').hasChild(auth.uid)",
".write" : "root.child('admins').hasChild(auth.uid)"
},
"users" : {
".indexOn": [ "organization" ],
"$user" : {
".read" : "data.child('organization').val() === root.child('users').child(auth.uid).child('organization').val()",
".write" : "root.child('admins').hasChild(auth.uid)"
}
},
"organizations" : {
".indexOn": [ "users", "employees" ],
"$organization" : {
".read" : "$organization === root.child('users').child(auth.uid).child('organization').val()",
".write" : "root.child('admins').hasChild(auth.uid)"
}
},
"employees" : {
".indexOn": [ "organization" ],
"$employee" : {
".read" : "data.child('organization').val() === root.child('users').child(auth.uid).child('organization').val()",
".write" : "data.child('organization').val() === root.child('users').child(auth.uid).child('organization').val()"
}
}
}
}
Now I can keep the data locked down fine in each collection, but the only way to get anything is to know the organization ID, get that organization, then get each and every employee by their ID. Although the docs above for structuring data (section: Joining Flattened Data) seem to suggest that it's fine to do this, coming from an OO and SQL background it feels very weird.. which usually means.. 'I'm doing it wrong'.
If anyone has any advice on whether I'm going down the right track, or what to try instead it would be greatly appreciated.
Thanks
Peter
After reading the docs and chatting with people in the firebase-community slack, I've come to the conclusion that I was on the right track.
I found using a compiler called "Bolt" (firebase-bolt in npm) extremely useful for generating the rules too.
Here's my structure, bolt rules and compiled JSON rules:
Structure
{
"admins" : {
"8UnM6LIiZJYAHVdty6gzdD8oVI42" : true
},
"organizations": {
"-JiGh_31GA20JabpZBfc" : {
"name" : "Comp1 Ltd",
"users" : {
"-JiGh_31GA20JabpZBfe" : true,
"-JiGh_31GA20JabpZBff" : true,
"-JiGh_31GA20JabpZBea" : true
},
"employees" : {
"-JiGh_31GA20JabpZBeb" : true,
"-JiGh_31GA20JabpZBec" : true
}
},
"-JiGh_31GA20JabpZBfd" : {
"name" : "company2 PLC",
"users" :{
"WgnHjk5D8xbuYeA7VDM3ngKwCYV2" : true
},
"employees" :{
"-JiGh_31GA20JabpZBce" : true
}
}
},
"users" : {
"8UnM6LIiZJYAHVdty6gzdD8oVI42": {
"firstName" : "Peter",
"lastName" : "Piper",
"email" : "peter.piper#testtest.com",
"organization" : ""
},
"-JiGh_31GA20JabpZBfe" : {
"firstName" : "Joe",
"lastName" : "Blogs",
"email" : "joe.blogs#co1.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"-JiGh_31GA20JabpZBff" : {
"firstName" : "Sally",
"lastName" : "McSwashle",
"email" : "sally.mcswashle#co1.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"-JiGh_31GA20JabpZBea" : {
"firstName" : "Eva",
"lastName" : "Rushtock",
"email" : "eva.rushtock#payrollings.com",
"organization" : "-JiGh_31GA20JabpZBfc"
},
"WgnHjk5D8xbuYeA7VDM3ngKwCYV2" : {
"firstName" : "test",
"lastName" : "user",
"email" : "test.user#google.com",
"organization" : "-JiGh_31GA20JabpZBfd"
}
},
"employees" : {
"-JiGh_31GA20JabpZBeb" : {
"organization" : "-JiGh_31GA20JabpZBfc",
"firstName" : "Johnny",
"lastName" : "Baggs",
"email" : "j.baggss#financeco.com",
"employeeNumber" : "ASV123456"
},
"-JiGh_31GA20JabpZBec" : {
"organization" : "-JiGh_31GA20JabpZBfc",
"firstName" : "Maheswari",
"lastName" : "Sanjal",
"email" : "mahe.sanjal#financeco.com",
"employeeNumber" : "ASV111111"
},
"-JiGh_31GA20JabpZBce" : {
"organization" : "-JiGh_31GA20JabpZBfd",
"firstName" : "Fedde",
"lastName" : "le Grande",
"email" : "fedde.grande#payrollings.com",
"employeeNumber" : "ASV111111"
}
}
}
Bolt Rules
// **********
// FUNCTIONS
// **********
function isAdmin (auth) {
return root.admins[auth.uid] != null
}
function isInSameOrganization(auth, orgUid) {
return root.users[auth.uid].organization === orgUid
}
// **********
// PATHS
// **********
path /admins {
read() { isAdmin(auth) }
write() { isAdmin(auth) }
}
path /users {
index() { ["organization"] }
write() { isAdmin(auth) }
}
path /users/{id} is User {
read() { isInSameOrganization(auth, id) || isAdmin(auth) }
}
path /organizations {
write() { isAdmin(auth) }
}
path /organizations/{id} is Organization {
read() { isInSameOrganization(auth, id) }
}
path /employees {
index() { ["organization"] }
write() { isInSameOrganization(auth, this.organization) || isAdmin(auth) }
}
path /employees/{id} is Employee {
read() { isInSameOrganization(auth, id) || isAdmin(auth) }
}
// **********
// TYPES
// **********
type OrganizationID extends String {
validate() { root.organizations[this] != null }
}
type UserID extends String {
validate() { root.users[this] != null }
}
type EmployeeID extends String {
// Validate that the user ID exists in the employees node (read rule access should prevent us reading a employees that isn't in our org)
validate() { root.employees[this] != null }
}
type Email extends String {
validate() {
return this.matches(/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}$/i);
}
}
type User {
firstName: String,
lastName: String
email: Email,
organization: OrganizationID
}
type Employee {
organization: OrganizationID,
firstName: String,
lastName: String,
email: Email,
employeeNumber: String
}
type Organization {
name: String,
users: Map<UserID, Boolean> | Null,
employees: Map<EmployeeID, Boolean> | Null
}
JSON Rules (generated by Bolt)
{
"rules": {
"admins": {
".read": "root.child('admins').child(auth.uid).val() != null",
".write": "newData.parent().child('admins').child(auth.uid).val() != null"
},
"users": {
".write": "newData.parent().child('admins').child(auth.uid).val() != null",
".indexOn": [
"organization"
],
"$id": {
".validate": "newData.hasChildren(['firstName', 'lastName', 'email', 'organization'])",
"firstName": {
".validate": "newData.isString()"
},
"lastName": {
".validate": "newData.isString()"
},
"email": {
".validate": "newData.isString() && newData.val().matches(/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\\\.[A-Z]{2,4}$/i)"
},
"organization": {
".validate": "newData.isString() && newData.parent().parent().parent().child('organizations').child(newData.val()).val() != null"
},
"$other": {
".validate": "false"
},
".read": "root.child('users').child(auth.uid).child('organization').val() == $id || root.child('admins').child(auth.uid).val() != null"
}
},
"organizations": {
".write": "newData.parent().child('admins').child(auth.uid).val() != null",
"$id": {
".validate": "newData.hasChildren(['name'])",
"name": {
".validate": "newData.isString()"
},
"users": {
"$key1": {
".validate": "newData.parent().parent().parent().parent().child('users').child($key1).val() != null && newData.isBoolean()"
},
".validate": "newData.hasChildren()"
},
"employees": {
"$key2": {
".validate": "newData.parent().parent().parent().parent().child('employees').child($key2).val() != null && newData.isBoolean()"
},
".validate": "newData.hasChildren()"
},
"$other": {
".validate": "false"
},
".read": "root.child('users').child(auth.uid).child('organization').val() == $id"
}
},
"employees": {
".write": "newData.parent().child('users').child(auth.uid).child('organization').val() == newData.child('organization').val() || newData.parent().child('admins').child(auth.uid).val() != null",
".indexOn": [
"organization"
],
"$id": {
".validate": "newData.hasChildren(['organization', 'firstName', 'lastName', 'email', 'employeeNumber'])",
"organization": {
".validate": "newData.isString() && newData.parent().parent().parent().child('organizations').child(newData.val()).val() != null"
},
"firstName": {
".validate": "newData.isString()"
},
"lastName": {
".validate": "newData.isString()"
},
"email": {
".validate": "newData.isString() && newData.val().matches(/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\\\.[A-Z]{2,4}$/i)"
},
"employeeNumber": {
".validate": "newData.isString()"
},
"$other": {
".validate": "false"
},
".read": "root.child('users').child(auth.uid).child('organization').val() == $id || root.child('admins').child(auth.uid).val() != null"
}
}
}
}
I'm still finding bugs in this, but I think it's showing progress. Just to note that there are some good official & unofficial Firebase videos on Youtube, the docs are fairly decent for the most part, and the firebase-community seems to be friendly. So any new comers like me, you know where to start.
I have a node in my realtime database with thousands of children, and want to filter on these, both quick and bandwidth saving (the latter is maybe not that important at this point, but might be when my data grows).
What is the best way of structuring this to avoid fetching all the items and doing the filtering on the client?
Here is what i'm planning on implementing, but as I have no experience with Firebase or other NoSQL databases, I do need some input :)
{
"items" : {
"item1" : {
"name" : "Item 1",
"filters": {
"filter1" : true,
"filter2" : true,
"filter3" : true
}
},
"item2" : {
"name" : "Item 2",
"filters": null
},
"item3" : {
"name" : "Item 3",
"filters": {
"filter2" : true
}
},
"item4" : {
"name" : "Item 4",
"filters": {
"filter2" : true,
"filter3" : true
}
},
"item5" : {
"name" : "Item 5",
"filters": {
"filter3" : true
}
}
// Thousands of items
},
"items_by_filter1" : {
"item1" : true
},
"items_by_filter2" : {
"item1" : true,
"item3" : true
},
"items_by_filter3" : {
"item1" : true,
"item4" : true,
"item5" : true
}
}
Am I overthinking this, or is this a good approach? What if I want to filter on several filters, should I follow the same approach and add something like this for all filter combinations (probably a struggle to maintain)?
"items_by_filter2_and_filter3" : {
"item1" : true,
"item4" : true
}
I use Firebase via REST API. I have following database structure:
{
"categories" : {
"Cat1" : {},
"Cat2" : {},
"Cat3" : {},
"Cat4" : {}
},
"items" : {
"item1" : {
"categories": ["Cat1", "Cat3"]
},
"item2" : {
"categories": ["Cat1", "Cat3"]
},
"item3" : {
"categories": ["Cat1", "Cat2", "Cat3"]
},
"item4" : {
"categories": ["Cat4"]
}
}
}
As you could see we have relations of type "N <-> N" between categories and items (one category could have several items and one item could be in several categories).
Now I want to get all items of Cat1 via Firebase REST API, but I can not do it.
As we know arrays are stored in the Firebase like map with integral indexes:
"categories": {
"0": "Cat1",
"1": "Cat2",
"2": "Cat3",
}
So, I added ".indexOn": ["categories/*"] to Realtime Database Rules and tried to call this:
curl 'https://...firebaseio.com/...json?orderBy="categories/*"&equalTo="Cat1"'
But I got only this: { }
So, I think that regular expressions do not work in Firebase queries, because this worked:
".indexOn": ["categories/0"] in Realtime Database Rules and
curl 'https://...firebaseio.com/...json?orderBy="categories/0"&equalTo="Cat1"'
Of course, I could change the database model to something like this:
{
"categories" : {
"Cat1" : {},
"Cat2" : {},
"Cat3" : {},
"Cat4" : {}
},
"items" : {
"item1" : {},
"item2" : {},
"item3" : {},
"item4" : {}
},
"category-items": {
"Cat1": ["item1", "item2", "item3"],
"Cat2": ["item3"],
"Cat3": ["item1", "item2", "item3"]
"Cat4": ["item4"]
}
}
And get the category-items and iterate through the Cat1 array, but then I must to call REST API read method too many times (one REST API call for every item in the category). So, it is too expensive.
So, could anybody help me with getting all items in a category in origin database model?
UPDATE
The final model is:
{
"categories" : {
"Cat1" : {},
"Cat2" : {},
"Cat3" : {},
"Cat4" : {}
},
"items" : {
"item1" : {
"Cat1": true,
"Cat3": true,
},
"item2" : {
"Cat1": true,
"Cat3": true,
},
"item3" : {
"Cat1": true,
"Cat2": true,
"Cat3": true,
},
"item4" : {
"Cat4": true
}
}
}
Also I added
{
rules": {
...
"items": {
".indexOn": [ "Cat1", "Cat2", "Cat3", "Cat4" ]
}
}
}
to Realtime Database Rules, and REST API call is
curl 'https://...firebaseio.com/items.json?orderBy="Cat1"&equalTo=true'
Thanks to Vladimir Gabrielyan
Here is the structure which I would suggest to have.
{
"categories" : {
"Cat1" : {
"items": {
"item1":{/*Some item info*/},
"item2":{/*Some item info*/}
}
},
"Cat2" : {
"items": {
"item3":{/*Some item info*/}
}
},
},
"items" : {
"item1" : {
"categories": {
"Cat1": true,
}
},
"item3" : {
"categories": {
"Cat2": true,
"Cat3": true
}
}
}
}
Inside Cat1/Items/{itemId} and items/{itemId} you need to duplicate your item information, but I think that is okay.
Also see this article. https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html
Wow! Thank you very much! Your suggestion with replace
"item1" : {
"categories": ["Cat1", "Cat3"]
},
to
"item1" : {
"Cat1": true,
"Cat3": true
},
can solve the problem, but then I will have to add every Cat to .indexOn in Realtime Database Rules, but this is not so big problem as origin problem.
But I think that
"categories" : {
"Cat1" : {
"items": {
"item1":{/*Some item info*/},
"item2":{/*Some item info*/}
}
},
"Cat2" : {
"items": {
"item3":{/*Some item info*/}
}
},
}
is not a good idea in my case because then we get many spare data every time we get information about Cat (when we no need list of items, only metadata of Cat). So, I suggest following model:
{
"categories" : {
"Cat1" : {},
"Cat2" : {},
"Cat3" : {},
"Cat4" : {}
},
"items" : {
"item1" : {
"Cat1": true,
"Cat3": true,
},
"item2" : {
"Cat1": true,
"Cat3": true,
},
"item3" : {
"Cat1": true,
"Cat2": true,
"Cat3": true,
},
"item4" : {
"Cat4": true
}
}
}
I am wondering if it's possible to do the firebase authentication on strings? I have seen it being done on keys like -XDhabsuduydvtest <- random test key.
Now i have this structure:
{
"conversations" : {
"person1" : {
"person2" : {
"0" : 0,
"last_read" : 1460377167535
}
},
"person2" : {
"person1" : {
"0" : 0,
"last_read" : 1460377125515
}
}
},
"messages" : {
"eb-uuid-729fc0ac-49b8-48fa-a2ff-f2ada67b9e4c-person1" : {
"body" : "Dit is een test vanuit iOS",
"date" : 1460383996536,
"sender" : "eb-uuid-729fc0ac-49b8-48fa-a2ff-f2ada67b9e4c"
},
"person1-person2" : {
"-KF49xHKqnDawywJ9H0b" : {
"body" : "test message",
"date" : 1460375639190,
"sender" : "person1"
},
"-KF4Fc1KHH31O4_l0QWh" : {
"body" : "new",
"date" : 1460377125013,
"sender" : "person2"
}
}
},
"users" : {
"eb-uuid-729fc0ac-49b8-48fa-a2ff-f2ada67b9e4c" : {
"chat_enabled" : true,
"email" : "test#gmail.com",
"first_name" : "John",
"last_name" : "Smith",
"provider" : "password",
"push_muted" : false,
"push_token" : "some-push-token",
"uid" : "729fc0ac-49b8-48fa-a2ff-f2ada67b9e4c",
"username" : "johnsmith"
},
"person1" : {
"first_name" : "person",
"last_name" : "one"
},
"person2" : {
"first_name" : "person",
"last_name" : "two"
}
}
}
plus some security rule i tried, obviously i'd like to check if the uuid's are the same, and not only if one exists
{
"rules": {
"messages": {
"$conv":{
//Person can only read a conversation he/she is participating in
".write": true,
".read": true,
".indexOn": ["date"]
}
},
"users":{
"$ebuuid":{
".write": "root.child('users').child($ebuuid).hasChild('uid')",
".read": "root.child('users').child($ebuuid).hasChild('uid')"
}
},
"conversations":{
".write": "data.child('uid').val() === auth.uid",
".read": true
}
}
}
(Replaced images with text)
I'm really not sure how to go from here now .. the user has some uid but i'm not sure how to check it with whether he or she can post messages etc ..