Firebase Rule for Data Validation - javascript

Assuming a data structure like below, I want a rule that disallows adding new car makes, for example users cannot add "toyota". So, I need to .validate such that the .update must match an existing make.
I have tried using $cars with ".validate": "newData.val().contains($cars)" and all kind of other ways with no luck. Any help is appreciated.
My code is:
function setModel(model,make,key){
if (model && make && key){
var carsRef = ref.child('cars');
var makeRef = carsRef.child(make);
var modelRef = makeRef.child(model);
var obj = {};
obj[key] = true;
modelRef.update(obj, onComplete);
}
}
The firebase looks like:
{
"cars" : {
"chevrolet" : {
"silverado" : {
"id192874623" : true,
"id786766663" : true
}
},
"ford" : {
"taurus" : {
"id736273627" : true
}
},
"honda" : {
"accord" : {
"id635263535" : true
}
}
}}

To disallow adding new car brands:
"cars": {
"$brand": {
".validate": "data.exists()"
}
}
This is covered in the section on existing data vs new data of the documentation.

Related

Firebase query delete specific value from database

I have this data on my firebase:
transportation: {
"car" : {
"bus" : {
"toyota" : false,
"bmw" : true
},
"suv" : {
"honda" : false,
"toyota" : true,
}
}
}
I want to delete all child that have "false" value data so that my data looks like this:
transportation: {
"car" : {
"bus" : {
"bmw" : true
},
"suv" : {
"toyota" : true,
}
}
}
This is code,
var ref = firebase.database().ref().child('transportation/')
ref.once("value")
.then(function(snapshot) {
data = snapshot.val();
for (var i=0;i < Object.keys(data).length;i++){
Object.keys(data)[i].forEach(function(childSnapshot) {
if(childSnapshot.val() == "false"){
childSnapshot.ref.remove();
}
});
}
}).catch(function(error) {alert("Data could not be deleted." + error);}););
In order to delete record from fairbase with its value, bellow may work:
var dB = firebase.database()
dB.ref('transportation/car').once('value', snap={
snap.forEach(s =>{
var obj =s.val();
var keys = s.key;
for (var key in obj ) {
if (!obj[key]) {
// In order to delete: set the path null
dB.ref('transportation/car/' + keys + "/" + key).set(null);
}
}
});
});
To delete data with specific value which false in your case . We needs to fetch all data for a node and then map through the data using keys to delete the data with exact value of object with value false.
let transportationRef = firebase.database().ref().child('transportation/')
transportationRef.child("car").once('value', s => {
if (s.exists()) {
// map through objects returned from transportationRef and map through the objects
Object.keys(s.val()).map(k => {
// deleting the node which contains `false` as value
if(s.val()[k]=="false"){
s.ref.remove()
}
})
}
})

Cloud Functions for Firebase - Remove oldest child

I have a onWrite cloud function set up to listen for when a user updates something. I'm trying to delete the oldest child if there are more than 3, this is there I'm at:
exports.removeOld = functions.database.ref('/users/{uid}/media').onWrite(event => {
const uid = event.params.uid
if(event.data.numChildren() > 3) {
//Remove Oldest child...
}
})
Each of these children has a "timestamp" key.
{
"users" : {
"jKAWX7v9dSOsJtatyHHXPQ3MO193" : {
"media" : {
"-Kq2_NvqCXCg_ogVRvA" : {
"date" : 1.501151203274347E9,
"title" : "Something..."
},
"-Kq2_V3t_kws3vlAt6B" : {
"date" : 1.501151232526373E9,
"title" : "Hello World.."
}
"-Kq2_V3t_kws3B6B" : {
"date" : 1.501151232526373E9,
"title" : "Hello World.."
}
}
}
}
}
So in the above example, when the text value is added to "media", the oldest would be delete.
This sample should help you.
You need something like that :
const MAX_LOG_COUNT = 3;
exports.removeOld = functions.database.ref('/users/{uid}/media/{mediaId}').onCreate(event => {
const parentRef = event.data.ref.parent;
return parentRef.once('value').then(snapshot => {
if (snapshot.numChildren() >= MAX_LOG_COUNT) {
let childCount = 0;
const updates = {};
snapshot.forEach(function(child) {
if (++childCount <= snapshot.numChildren() - MAX_LOG_COUNT) {
updates[child.key] = null;
}
});
// Update the parent. This effectively removes the extra children.
return parentRef.update(updates);
}
});
});
You can find all Cloud Functions for Firebase samples here.

Mental JSON cartwheels, match values by key

I have this JSON object:
{
"foo" : {
"58eedc4298d1712b870c8e0a" : false,
"58eedc4298d1712b870c8e06" : true,
"58eedc4198d1712b870c8e05" : true
},
"bar" : {
"58eedc4298d1712b870c8e0a" : "git",
"58eedc4298d1712b870c8e06" : "svn",
"58eedc4198d1712b870c8e05" : "hg"
},
}
I want to get an object that looks like:
{
git: false,
svn: true,
hg: true
}
every algorithm I have come up with is very verbose, anybody think of something quick and clever?
var newObj = {};
for (let property in obj.bar) {
if obj.bar.hasOwnProperty(property){
newObj[obj.bar[property]] = obj.foo[property];
}
}
I'm really not a js dev, but this is where I would start.
The code above is written without any kind of syntax checking. I have no idea if it will actually compile.
If you are using lodash (if not you should), you can do in following way.
var _ = require("lodash");
var data = {
"foo": {
"58eedc4298d1712b870c8e0a": false,
"58eedc4298d1712b870c8e06": true,
"58eedc4198d1712b870c8e05": true
},
"bar": {
"58eedc4298d1712b870c8e0a": "git",
"58eedc4298d1712b870c8e06": "svn",
"58eedc4198d1712b870c8e05": "hg",
"58eedc4198d1712b870c8e06": "fa"
},
}
var keys = _.keys(data.bar);
var result = {};
_.forEach(keys, function (key) {
result[data.bar[key]] = data.foo[key] ? data.foo[key] : false;
});
console.log(result);

Firebase v3 Query by Grandchild

When registering new email/password type users, I need to make user that the displayName that they enter does not already exist in my Realtime Database before calling .createUserWithEmailAndPassword. So I need a query. I need to get a list of all displayName's in my users branch. I am confused as to how to gather this for each user which is denoted by each users auth.uid.
What would the retrieval look like? I am thinking something like:
firebase.database().ref('users/' + allUserIds).equalTo('Joe');
but I know that allUserIds is not valid. Can someone help me with this?
{
"users" : {
"6mJb9vtpbDelyyjirKEf6sSEj8h1" : {
"name" : "asdfs#asdf.com",
"provider" : "password",
"displayName" : "Joe"
},
"T7D7qEOPPHXjKSzglKheGJDQNkE3" : {
"name" : "gfdsdf#hlkjh.com",
"provider" : "password",
"displayName" : "Jane"
},
"kTG9R0V4aXYsogQfgF633KFYtzV2" : {
"name" : "Andre3000",
"provider" : "google.com",
"displayName" : "Andre"
}
}
}
You'd use Firebase queries for that:
var users = firebase.database().ref('users');
var joes = users.orderByChild('displayName').equalTo('Joe');
joes.once('value', function(snapshot) {
console.log('A Joe does '+(snapshot.exists()?'':'not ')+' exist')
});
Don't forget to define an index on users:
{
"rules": {
"users": {
".indexOn": "displayName"
}
}
}
Just thought I'd share my somewhat fleshed out solution. Call with myApp.displayNameExists('Joe').
var myApp = (function() {
var pub = {};
pub.displayNameExists = function(name) {
var users = firebase.database().ref('users');
var duplicate = users.orderByChild('displayName').equalTo(name);
duplicate.once('value').then(function(snap) {
if (snap.val()) {
console.log('found. ask for new display name');
} else {
console.log('name unique. ok to write this user to db');
}
}, function(error) {
// The Promise was rejected.
console.error(error);
});
}
//API
return pub;
}());

how to nest mongodb queries through node.js?

I am having a collection of users of the type -
{
"_id" : ObjectId("56f60e4eea8af4670408483e"),
"twitterHandle" : "shrutip",
"firstName" : "Shruti",
"lastName" : "Patil",
"emailID" : "shrutip#gmail.com",
"password" : "91382451347786e9b8f2f3817b27a2adfec1880c",
"phoneNumber" : "98739458789",
"location" : "San Jose",
"birthYear" : 1992,
"birthMonth" : 1,
"birthDay" : 10,
"followers" : [
"abhayp",
"anupd",
"lubdhal",
"poojag",
"prashantb",
"pratiksanglikar",
"shaileshyedge",
"shrutip"
],
"following" : [
"abhinavk",
"anupd",
"hiteshn",
"lubdhal",
"omkarn",
"poojag",
"pratiksanglikar",
"shaileshyedge",
"shrutip"
],
"tweets" : [
{
"tweet_id" : "3c50e98cf0c2298f40f98a013cd4a18a1443b7ac",
"tweet_text" : "At BJP youth wing meet, seniors worry over #JNU controversy, and not #RamTemple.",
"createdOn" : ISODate("2016-03-07T23:37:27Z"),
"tags" : [
"JNU",
"RamTemple"
]
}
]
}
I want to create feed (all tweets of the users the given user is following in ascending order of date) for any given user. I got the list of users which the given user is following, but I need to find the tweets of the found users. How do I do it in node.js? How to nest these queries?
What I've done so far is listed below -
var cursor = MongoDB.collection("users").find({
"twitterHandle": twitterHandle
});
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
var followingCursor = MongoDB.collection("users").find( { twitterHandle: { $in: doc.following } } );
followingCursor.each(function (err, following) {
if(following != null) {
feed.push(following.tweets);
}
});
promise.resolve(feed);
}
});
But somehow, the promise gets resolved before the second query executes.
How do I ensure that all the iterations of followingCursor.each are executed before I return the promise?
Eventually I found out the answer myself.
if (doc != null) {
var followingCursor = MongoDB.collection("users").find( { twitterHandle: { $in: doc.following } } );
followingCursor.each(function (err, following) {
if(following != null) {
feed.push(following.tweets);
}
});
promise.resolve(feed);
}
In the above code, promise should be resolved if the following != null condition fails.
Apparently MongoDB driver returns null when the values in cursor end. The correct code is as following -
if (doc != null) {
var followingCursor = MongoDB.collection("users").find( { twitterHandle: { $in: doc.following } } );
followingCursor.each(function (err, following) {
if(following != null) {
feed = feed.concat(following.tweets);
} else {
promise.resolve(feed);
}
});
}

Categories