How to orderByChild in nested Child in angularfire? - firebase

My firebase database structure is as below. I would like to search with a particular "Info/Email", let's say "abc#abc.com".
{
"-KhWrBcYyMluJbK7QpnK" : {
"Info" : {
"Email" : "xyz#gmail.com"
},
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX0tgQvDtDYqt4XRoL" : {
"Info" : {
"Email" : "abc#abc.com"
},
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX1eo7uFnOxqncDXQ5" : {
"Info" : {
"Email" : "abc#abc.com"
},
"Settings" : {
"Status" : "Pending"
}
}
}
I added a rule too
"Invitation" : {
".indexOn": ["Info/Email","Settings/Status"]
}
My AngularFire code is as follows:
var rootRef = firebase.database().ref().child('Invitation');
var userInvitations = rootRef.child("Info").orderByChild("Email").equalTo("abc#abc.com");
var allInvitations = $firebaseArray(userInvitations);
But I am getting a FIREBASE WARNING: Using an unspecified index. Consider adding ".indexOn": "Email" at /Invitation/Info to your security rules for better performance. and of course I am not receiving any data.
What are the mistakes I made here? Also can I add multiple orderByChild, for example: if I want to find details of the record, which has "Info/Email" equal to "abc#abc.com" and "Settings/Status" equal to "Pending" ?

The Firebase API only allows you to filter children one level deep
So with reference to your data structure:
if it were to be this way,
{
"-KhWrBcYyMluJbK7QpnK" : {
"Email" : "xyz#gmail.com",
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX0tgQvDtDYqt4XRoL" : {
"Email" : "abc#abc.com",
"Settings" : {
"Status" : "Accepted"
}
},
"-KhX1eo7uFnOxqncDXQ5" : {
"Email" : "abc#abc.com",
"Settings" : {
"Status" : "Pending"
}
}
}
You should write your rules this way instead.
"Invitation" : {
"Info" : {
".indexOn": "Email",
},
"Settings" : {
".indexOn": "Status",
}
}
Then you will be able to query the data
var allInvitations = [];
var rootRef = firebase.database().ref().child('Invitation');
var userInvitations = rootRef.orderByChild("Email").equalTo("abc#abc.com");
userInvitations.on('value', snap => {
var invitations = snap.val()
for (prop in invitations ) {
allInvitations.push(invitations[prop ]);
}
console.log(allInvitations);
})

Related

Meteor - UserIsInRole always returning false

I Have added allaning:roles in my meteor-react project but
Roles.userIsInRole(Meteor.userId(), ["ADMIN"]) always returning false.
I have roles in my mongo as follows,
{ "_id" : "9B3D757wQA9Mz4RGt", "name" : "BUYER" }
{ "_id" : "PDCJH8D6JDo9fttFj", "name" : "ADMINKAMB" }
{ "_id" : "XFGsrfB3Xsm6F8LbQ", "name" : "SELLER" }
{ "_id" : "hDLSvdo6wMnF47BBz", "name" : "ADMIN" }
{ "_id" : "ADMINKAMB", "children" : [ ] }
if you remove the autopublish from yours packages, try to add this code
For my case, I create a file /imports/startup/server/publications/index.js
Meteor.publish(null, function() {
if (this.userId) {
return Meteor.roleAssignment.find({ 'user._id': this.userId });
}
return this.ready();
});
Then in server/main.js
import '/imports/startup/server/publications'

Get list of items based on user id (from array of user id) firebase Realtime Database

I want to fetch the list of devices based on user id from the array of users list. data base shown below.
{
"devices" : {
"aglow6534" : { // Device ID
"icon" : "switch",
"name" : "AC",
"state" : {
"switch" : true
},
"type" : "RLY",
"users" : {
"rIXU5HucbVMTt3foI3AG7q5wBND3" : true // User ID
}
},
"aglow8728" : { // Device ID
"icon" : "bulb",
"name" : "bulb",
"state" : {
"intensity" : 45,
"switch" : true
},
"type" : "DIMR",
"users" : {
"YBJAlwc0vQSmd1TYe190Of8V57y1" : true, // User ID
"rIXU5HucbVMTt3foI3AG7q5wBND3" : true // User ID
}
}
},
"users" : {
"YBJAlwc0vQSmd1TYe190Of8V57y1" : { // User ID
"age" : 28,
"name" : "vipul garg"
},
"rIXU5HucbVMTt3foI3AG7q5wBND3" : { // User ID
"age" : 17,
"name" : "puneet"
}
}
}
These are my rules, i tried my best to fetch data, please help i almost spend 2 days on it.
{
"rules": {
"devices" : {
".read" : "root.child('users').child(auth.uid).child('devices').hasChild(data.child('/').val())",
}
},
}
Required Result:
Example 1: let User Id: YBJAlwc0vQSmd1TYe190Of8V57y1
"devices" : {
"aglow8728" : {
"icon" : "bulb",
"name" : "bulb",
"state" : {
"intensity" : 45,
"switch" : true
},
"type" : "DIMR",
"users" : {
"YBJAlwc0vQSmd1TYe190Of8V57y1" : true,
"rIXU5HucbVMTt3foI3AG7q5wBND3" : true
}
}
},
Example 2: let User Id: rIXU5HucbVMTt3foI3AG7q5wBND3
"devices" : {
"aglow6534" : {
"icon" : "switch",
"name" : "AC",
"state" : {
"switch" : true
},
"type" : "RLY",
"users" : {
"rIXU5HucbVMTt3foI3AG7q5wBND3" : true
}
},
"aglow8728" : {
"icon" : "bulb",
"name" : "bulb",
"state" : {
"intensity" : 45,
"switch" : true
},
"type" : "DIMR",
"users" : {
"YBJAlwc0vQSmd1TYe190Of8V57y1" : true,
"rIXU5HucbVMTt3foI3AG7q5wBND3" : true
}
}
},
I think you need to fully understand Firebase Realtime Database Rules first and other 8 links in Security & Rules section
Your rules is wrong on syntax. It should be something like this, maybe
{
"rules": {
"devices": {
"$devices_id": {
".read": "true",
".write": "false" // false if want to read only
}
},
"users": {
"$users_id": {
".read": "auth != null && auth.uid == $users_id" // this is for If you wanted to restrict access to this data such that only the logged-in user can see their own data
".write": "auth != null && auth.uid == $users_id"
}
}
}
}

Firebase realtime rules how to check if node with AutoID contains correct data

I am trying to write a firebase rule that checks to see if you have access to a child of one node by checking the data of another node. The issue I am having is accessing the other node's data because it is stored under an AutoId. How would I access the data under the AutoId?
Here is my database structure:
{
"products" : {
"Product001" : {
"ownerId" : "User002",
"productName": "Name"
},
"product002" : {
"ownerId" : "User001",
"productName": "Name"
}
},
"shares" : {
"share001" : {
"accepted" : true,
"ownerId" : "User002",
"productId" : "Product001",
"userEmail" : "example#email.com"
},
"share002" : {
"accepted" : true,
"ownerId" : "User001",
"productId" : "Product002",
"userEmail" : "email#exaple.com"
}
},
"users" : {
"User001" : {
"email" : "example#email.com",
"firstName" : "John",
"lastName" : "Smith"
},
"User002" : {
"email" : "email#example.com",
"firstName" : "John",
"lastName" : "Smith"
}
}
}
Here is the section of the rules that is causing me a problem:
"products":{
"$productId":{
".read":"root.child('shares').child($shareId).child('productId').val() === $productId && root.child('shares').child($shareId).child('ownerId').val() === auth.uid",
".write":"root.child('shares').child($shareId).child('productId').val() === $productId && root.child('shares').child($shareId).child('ownerId').val() === auth.uid"
}
}
Essentially, a user is only allowed to access a premises if they are in a share that contains their information.
Thank you for any advice.
There is no way in security rules to query or search another node, as the performance of that would be way too unreliable. So in your current data model it is not possible to allow the user access to a product if they have any shares for that product.
You'll need to have a list somewhere in a knowable path of the products the user can read. For example, say that you keep a list of the products the user is interested in:
"interests" : {
"User001" : {
"Product001": true,
"Product002": true
},
Now you can allow the user access to all products they follow with:
"products":{
"$productId":{
".read":"root.child('interests').child(auth.uid).child($productId).exists()",
".write": ...
}
}

How to do filter by keyword in Firebase?

I have a Firebase database structure like this
{
"5ZhJG1NACDdG9WoNZWrBoYGkIpD3" : {
"Company" : {
"5ZhJG1NACDdG9WoNZWrBoYGkIpD3" : {
"authTime" : 1532061957,
"companyName" : "Scopic Software",
"contactName" : "Hoang Scopic",
"email" : "hoang.trinh#scopicsoftware.com",
"firebaseID" : "5ZhJG1NACDdG9WoNZWrBoYGkIpD3",
"isFirstLogin" : false,
"phoneNumber" : "1234567890",
"schoolName" : "MIT",
"teachers" : {
"aOpjnzHpDiZ7uwQQqJoinGvM9ZD3" : "0"
}
}
}
},
"AhZc9B02goOtZ6qBNhz9W0K6Esg2" : {
"Subscription" : {
"-LHlQ4OhijzzFY5HZOT4" : {
"firebaseID" : "-LHlQ4OhijzzFY5HZOT4",
"period" : {
"endAt" : "1533194625",
"startAt" : "1531985025"
},
"status" : "trial"
}
},
"Teacher" : {
"AhZc9B02goOtZ6qBNhz9W0K6Esg2" : {
"authTime" : 1532061932,
"email" : "hoang.trinhj#gmail.com",
"firebaseID" : "AhZc9B02goOtZ6qBNhz9W0K6Esg2",
"isFirstLogin" : false,
"name" : "Hoang Trinh",
"schoolName" : "HUST",
"subscriptions" : {
"-LHlQ4OhijzzFY5HZOT4" : "0"
}
}
}
},
"aOpjnzHpDiZ7uwQQqJoinGvM9ZD3" : {
"Subscription" : {
"-LHlWnpNZazBC5lpXLi0" : {
"firebaseID" : "-LHlWnpNZazBC5lpXLi0",
"period" : {
"endAt" : "1533196388",
"startAt" : "1531986788"
},
"status" : "trial"
}
},
"Teacher" : {
"aOpjnzHpDiZ7uwQQqJoinGvM9ZD3" : {
"Company" : {
"5ZhJG1NACDdG9WoNZWrBoYGkIpD3" : "0"
},
"authTime" : 1532060884,
"email" : "piavghoang#gmail.com",
"firebaseID" : "aOpjnzHpDiZ7uwQQqJoinGvM9ZD3",
"isFirstLogin" : false,
"subscriptions" : {
"-LHlWnpNZazBC5lpXLi0" : "0"
}
}
}
},
"ooR32SjABdOYEkWX6dzy4fE5Kym1" : {
"Admin" : {
"email" : "admin#test.com",
"firstName" : "Hoang",
"lastName" : "Trinh",
"password" : "123456xx"
},
"isAdmin" : true
}
}
This is data in an existing system, so I can't change its structure.
Now I need to write an API to list these records filtered by "email" attribute there (it's nested inside a key).
How can I do a search for this email?
There is one solution that I thought about. It's just getting the whole json back and process data in code (not using Firebase database query functions).
But I can't do that, because AFTER filtering, I need to do paging also.
In order to make the pagination, I need to use query functions like "sortByChild" or "limitToLast", so I have to use these query functions with filtering.
Thank you.
EDIT:
My current implementation for pagination:
getUsers: async (page, perPage, searchTerm) => {
const db = fbAdmin.db();
let dbRef = await db.ref();
if (searchTerm) {
// TODO: Add filter logic here
}
let totalItems = await dbRef.once('value');
let totalItemsNumber = await Object.keys(totalItems.toJSON()).length;
// Calculate for pagination
let lastItemId;
if ((page - 1) * perPage + 1 > totalItemsNumber) {
lastItemId = null;
} else {
let lastItems = await dbRef.orderByKey().limitToLast((page - 1) * perPage + 1).once('value');
lastItemId = Object.keys(lastItems.toJSON())[0];
}
// Do the pagination
let snap;
let data;
if (lastItemId) {
snap = await dbRef.orderByKey().endAt(lastItemId).limitToLast(perPage).once('value');
data = snap.toJSON();
} else {
data = {};
}
let users = Object.keys(data).map(key => {
if (data[key][KEY]) { // Check if it's an admin
return {
role: TYPE_ADMIN,
email: data[key][KEY].email,
name: data[key][KEY].firstName + " " + data[key][KEY].lastName
}
} else if (data[key][Company.KEY]) { // Check if it's a company member
return {
role: TYPE_COMPANY_MEMBER,
email: data[key][Company.KEY][key].email,
name: data[key][Company.KEY][key].name,
schoolName: data[key][Company.KEY][key].schoolName
}
} else if (data[key][Teacher.KEY]) { // Check if it's a teacher
if (data[key][Teacher.KEY][key][Company.KEY]) { // Check if it's a company teacher
return {
role: TYPE_COMPANY_TEACHER,
email: data[key][Teacher.KEY][key].email,
name: data[key][Teacher.KEY][key].name,
schoolName: data[key][Teacher.KEY][key].schoolName,
subscription: data[key][Subscription.KEY]
}
} else { // Check if it's an individual teacher
return {
role: TYPE_INDIVIDUAL_TEACHER,
email: data[key][Teacher.KEY][key].email,
name: data[key][Teacher.KEY][key].name,
schoolName: data[key][Teacher.KEY][key].schoolName,
subscription: data[key][Subscription.KEY]
}
}
} else {
return null;
}
});
return users || null;
},

Client does not have permission to access the desired Firebase data

I have a page that is calling addCheckin() method which is inside a controller. In the controller, I am trying to create a reference as follows:
var ref = firebase.database().ref("users/" + $scope.whichuser + "/meetings/" +$scope.whichmeeting + "/checkins");
$scope.whichuser and $scope.whichmeeting are the $routeParams that I am passing from another route.
Here's my checkin controller-
myApp.controller("CheckinsController",
['$scope','$rootScope','$firebaseArray','$routeParams','$firebaseObject',
function($scope,$rootScope,$firebaseArray,$routeParams,$firebaseObject){
$scope.whichuser = $routeParams.uid;
$scope.whichmeeting = $routeParams.mid;
var ref = firebase.database().ref("users/" + $scope.whichuser + "/meetings/" +$scope.whichmeeting + "/checkins");
$scope.addCheckin = function(){
var checkinInfo = $firebaseArray(ref);
var data={
firstname:$scope.firstname,
lastname:$scope.lastname,
email:$scope.email,
date:firebase.database.ServerValue.TIMESTAMP
}
checkinInfo.$add(data);
}
}]);/*controller*/
There are two errors that I am getting here-
Error 1:
Error: permission_denied at /users/Vp2P1MqKm7ckXqV2Uy3OzTnn6bB3/meetings: Client doesn't have permission to access the desired data.
Error 2:
Error: permission_denied at /users/Vp2P1MqKm7ckXqV2Uy3OzTnn6bB3/meetings/-KT5tqMYKXsFssmcRLm6/checkins: Client doesn't have permission to access the desired data.
And this is what I am trying to achieve:
Here's my JSON tree of the database:
{
"users" : {
"43ZU72ndoKb9LSEjBODKXe3nrou1" : {
"email" : "roy#123.com",
"firstname" : "Roy",
"lastname" : "Marshal",
"regUser" : "43ZU72ndoKb9LSEjBODKXe3nrou1"
},
"BHcYb40FC8YlCKL54ngyMhxPx2q1" : {
"date" : 1475574109981,
"email" : "sky#on.com",
"firstname" : "Sky",
"lastname" : "Thakur",
"meetings" : {
"-KTE3_45wXBqd-_yR1xv" : {
"date" : 1475574125198,
"name" : "ARET"
}
},
"regUser" : "BHcYb40FC8YlCKL54ngyMhxPx2q1"
},
"Vp2P1MqKm7ckXqV2Uy3OzTnn6bB3" : {
"email" : "jon#me.com",
"firstname" : "John",
"lastname" : "Cena",
"meetings" : {
"-KT5tqMYKXsFssmcRLm6" : {
"date" : 1475437094667,
"name" : "hourly"
},
"-KTAvH-ZkWyxrJrK_SDb" : {
"date" : 1475521356544,
"name" : "Hourly"
},
"-KTAwV69txdeT4i_horE" : {
"date" : 1475521676006,
"name" : "asdfg"
},
"-KTAwkH35EyPQZ17DmN9" : {
"date" : 1475521742244,
"name" : "qwerty"
},
"-KTAwsrqe24e8wFfRxpN" : {
"date" : 1475521777422,
"name" : "asfdsf"
},
"-KTAyYPSZLQUtOJ4g8Ak" : {
"date" : 1475522213781,
"name" : "Yearly"
},
"-KTB05PfXZLLk9Of3_Nb" : {
"date" : 1475522881473,
"name" : "Meet"
},
"-KTBG2cP9YLoP4lalN5M" : {
"date" : 1475527064378,
"name" : "JOI"
}
},
"regUser" : "Vp2P1MqKm7ckXqV2Uy3OzTnn6bB3"
}
}
}
My database rules are:
{
"rules": {
".read": true,
".write": true
}
}
I also posted this question before, but didn't get any appropriate solution.

Resources