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;
}());
Related
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.
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);
}
});
}
I am working with Node JS and mongodb and I have a collection of documents with ids from 1-5000. However there are some ids that are missing and I want each document to have one ID.
Here is the code I'm working with:
MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
if(err) {
console.log("Unable to connect", err);
return;
}
console.log("We are connected");
var collection = db.collection('examples');
collection.aggregate(
[
{"$sort": {"user_id": 1} },
{"$out": "users"}
]
).toArray(function(err, docs) {
var toSave = [];
db.collection('users').find().toArray(function(err, docs){
docs.forEach(function(doc){
toSave.push(doc.user_id);
})
for (var i = 1; i < 5000; i++) {
if (toSave.indexOf(i) == -1) {
db.collection('examples').insert({
user_id: i,
create_dt: new Date()
})
}
}
console.log(toSave);
db.close()
})
});
});
I was hoping this would go through my toSave array and insert documents for each of the missing user_id's but when I check my database it only ever creates one document.
How can I get all of the documents to save in the database?
I agree with #Blakes. It appears to me that you really want to find documents containing a user_id field which must be updated, and then update that field with some appropriate value. For example, the user_id field might be null, or it contains a duplicate value. Suppose you have two documents that each have a user_id of 81:
{ "_id" : ObjectId("56c519bac62ffdbd22b000fd"), "user_id" : 81, "stuff" : 11 }
{ "_id" : ObjectId("56c519cbc62ffdbd22b000fe"), "user_id" : 81, "stuff" : 12 }
Changing the user_id field can be done by calling the updateOne() method of the MongoDB javascript driver.
Here is example code:
db.collection('examples2').find(query).toArray(function(err, docs) {
if (err) throw (err)
docs.forEach(function (doc) {
if (doc.user_id === 81) {
dcnt++
im_array.push(doc._id)
console.dir(doc)
}
if (doc.user_id === "") { //empty?
dcnt++
im_array.push(doc._id)
console.dir(doc)
}
})
})
setTimeout(function() {
console.log("\nPrinting list of objectids\n")
for (var i = 0; i < im_array.length; i++) {
console.log(im_array[i])
}
console.log("\nUpdating Documents...\n")
for (var j = 0; j < im_array.length; j++) {
idObj = new ObjectID(im_array[j])
db.collection('examples2').updateOne( { "_id" : idObj }, { "$set" : { "user_id" : j + 27 } }, function(err2, doc2) {
if (err2) throw err2
})
}
}, 5000)
setTimeout(function() {
db.collection('examples2').find( { "user_id" : 10 })
console.log('\nTotal number of documents processed ' + dcnt + '\n')
db.close()
}, 12000)
Since processing is asynchronous, I'm being a bit crude and using setTimeout() where perhaps using promises-based processing is better.
In any case, the above code will update the documents containing a user_id field equal to 81:
{ "_id" : ObjectId("56c519bac62ffdbd22b000fd"), "user_id" : 27, "stuff" : 11 }
{ "_id" : ObjectId("56c519cbc62ffdbd22b000fe"), "user_id" : 28, "stuff" : 12 }
Consider creating a unique index on the user_id field as well. This way, any code that attempts to create or update a document without including a properly formatted user_id will fail.
I have Firebase entries in /items with the properties title and points. I am trying to check to see if an item of the same title exists before entering a new one.
This is what I have but it does not happen:
app.controller('ItemController', function($scope, FURL, $firebase, $location, toaster) {
var ref = new Firebase(FURL);
var fbItems = $firebase(ref.child('items')).$asArray();
$scope.addItem = function(item) {
// var iItem = $scope.item.title;
var userId = $scope.item.title;
checkIfUserExists(userId);
};
function userExistsCallback(userId, exists) {
if (exists) {
alert('user ' + userId + ' exists!');
} else {
alert('user ' + userId + ' does not exist!');
}
}
function checkIfUserExists(userId) {
ref.child('items').once('value', function(snapshot) {
var exists = (snapshot.val() !== null);
userExistsCallback(userId, exists);
});
}
});
The Realtime Database is a key/value JSON database. This means that if you store a title name as a key, it will be super quick to look it up.
Take the following data for example.
{
"items": {
"title-1": {
"something": "foo"
},
"title-2": {
"something": "baz"
}
}
}
Now let's say we want to check to see if title-2 exists. We can do this with an easy read.
function checkForTitle(title, cb) {
var itemsRef = new Firebase('<my-firebase-app>/items');
var titleRef = itemRef.chld(title).once('value', function(snap) {
cb(snap.exists());
});
}
checkForTitle('title-2', function(doesExist) {
console.log(doesExist); // true
});
To make sure the check happens on the server, you can write a Security Rule for it. Or, better yet use the new Bolt Compiler.
{
"items": {
"$item": {
".write": "!data.exists()" // don't overwrite existing data
}
}
}
You should upgrade your AngularFire version. I noticed you're using $firebase().$asArray which means you're on the 0.9 version of AngularFire, which is unsupported. Look into upgrading to the 1.0+ version which is officially support by Firebase.
var mongoose = require('mongoose');
// defines the database schema for this object
var schema = mongoose.Schema({
projectName : String,
authorName : String
comment : [{
id : String,
authorName : String,
authorEmailAddress : { type : String, index : true }
}]
});
})
// Sets the schema for model
var ProjectModel = mongoose.model('Project', schema);
// Create a project
exports.create = function (projectJSON) {
var project = new ProjectModel({
projectName : projectJSON.projectName ,
authorName : projectJSON.authorName,
comment : [{
id : projectJSON.comments.id,
authorName : projectJSON.comments.authorName,
authorEmailAddress : projectJSON.authorEmailAddress
});
project.save(function(err) {
if (err) {
console.log(err);
}
else{
console.log("success");
}
});
}
Q: i would like to retrieve all comments (without other document fields) a specific user made across all projects
My attempt:
// assuming email address is unique per user, as user can always change displayName for instance
exports.allCommentsByUser = function(userEmail, callback){
ProjectModel.find(
{"comments.authorEmailAddress" : userEmail},
{ "projectName" : 1, "comments.authorEmailAddress" : 1 },
callback);
};
You can use the 2.2 aggregation framework for this type of query:
ProjectModel.aggregate([
{
// Only include the projectName and comments fields.
$project: { 'projectName': true, 'comments': true, '_id': false }
}, {
// Get all project docs that contain comments by this user
$match: { 'comments.authorEmailAddress': userEmail }
}, {
// Duplicate the project docs, one per comment.
$unwind: '$comments'
}, {
// Filter that result to just the comments by this user
$match: { 'comments.authorEmailAddress': userEmail }
}], callback
);