Javascript reading firebase list data - callback

I'm trying to read firebase data and then print the data to the console, but nothing makes it to the console.
function readData(){
var listRef = new Firebase('https://----.firebaseIO.com/');
listRef.on('child_added', function(snapshot) {
var msgData = snapshot.val();
console.log("Snapshot : " + msgData.message);
});//end snapshot
}//end readData
my firebase data looks like. This is right under the root.
{
"-J75NmiNt3blUhVDCWbc" : {
"from" : "Blah",
"message" : "Blah"
},
"-J75N2bNbDZpshEBG1yS" : {
"from" : "Jackson",
"message" : "BLAH BlaH"
},
"-J75PCsjFlbDQ3g9vKyb" : {
"from" : "fff",
"message" : "fff"
},
"-J75MvQQpRBB6s-l3KrQ" : {
"from" : "",
"message" : ""
},
"-J75OHX7rdE1K8wpvZOt" : {
"from" : "fff",
"message" : "ff"
}
} //end

EDIT: My original answer was completely missing question, rewritten for further smiting
Are you sure that you are getting the data within your Event? It would gracefully fail. Step through the debugger and make sure you are getting your actual object passed correctly. From their example on the chat tool They are binding to an event that pushes to the listRef object like this:
$('#messageInput').keypress(function (e) {
if (e.keyCode == 13) {
var name = $('#nameInput').val();
var text = $('#messageInput').val();
messagesRef.push({name:name, text:text});
$('#messageInput').val('');
}
});
My guess is that your snapshot variable is not accessible/null.

Related

Firebase gives sometimes only parts of my saved values and sometimes everything

I'm trying to code my own messenger. I saved the messages in Firebase database. I'm trying to access the messages with the normal way how I do it every time (database.database().reference().child("users")...., but it gives back only a few messages and only sometimes every message
I already tried it with .childAdded but it doesn't work either
func fetchMessages() {
self.messages.removeAll()
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("users").child(uid).child("chats").child(self.chatuid).child("messages")
ref.observeSingleEvent(of: .value) { (snap) in
guard let data = snap.value as? [String: AnyObject] else { return }
//MARK: data = (messageID, AnyObject)
for (messageID, _) in data {
ref.child(messageID).observeSingleEvent(of: .value) { (snap2) in
guard let data2 = snap2.value as? [String: AnyObject] else { return }
//MARK: data2 = ("message": String, "sentuid": String)
guard let message = data2["message"] as? String else { return }
guard let sentuid = data2["sentuid"] as? String else { return }
let messageToAppend = Message(sentuid: sentuid, message: message)
self.messages.append(messageToAppend)
self.messageTableView.reloadData()
}
}
}
}
//self.messages = Place where I save my fetched messages
Firebase-Structure:
{
"users" : {
"V3bLZu61KYTCG0uCWV8LH1f4rRJ3" : {
"chats" : {
"x3GzxwmyLbXrQNNyBF2a82KqrHa2" : {
"messages" : {
"20191014165454" : {
"message" : "Heyho",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165647" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165754" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165800" : {
"message" : "Fuchsloch",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165805" : {
"message" : "Jlksaö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165808" : {
"message" : "Jadfsk",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165811" : {
"message" : "Jskldflsö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014170041" : {
"message" : "JALSF",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"test" : {
"messange" : "test",
"sentUid" : "MatesForSports"
}
}
}
},
"username" : "Acc2"
},
"x3GzxwmyLbXrQNNyBF2a82KqrHa2" : {
"chats" : {
"V3bLZu61KYTCG0uCWV8LH1f4rRJ3" : {
"messages" : {
"20191014165454" : {
"message" : "Heyho",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165647" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165754" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165800" : {
"message" : "Fuchsloch",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165805" : {
"message" : "Jlksaö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165808" : {
"message" : "Jadfsk",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165811" : {
"message" : "Jskldflsö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014170041" : {
"message" : "JALSF",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"test" : {
"messange" : "test",
"sentUid" : "MatesForSports"
}
}
}
},
"username" : "Acc1"
}
}
}
I expected that the code would give back around 10 messages, but it gives sometimes 5, sometimes 3 or even only 2 messages
My firebase-structure of the messages is .child("messages"), then a unique id, then the actual message and the sender at one layer
Here's an an answer followed by a suggestion.
Let's start with replicating your structure using some hard coded values
users
uid_0
chats
chat_uid_0
messages
unique_id_0
msg: "My Message"
sent_uid: "uid_1"
unique_id_1
msg: "Hello, World"
sent_uid: "uid_3"
unique_id_2
msg: "another message"
sent_uid: "uid_2"
then the code to read in the messages, iterate over them and print out the msg and sent_uid
func readMessages() {
let usersRef = self.ref.child("users")
let messagesRef = usersRef.child("uid_0").child("chats").child("chat_uid_0").child("messages")
messagesRef.observeSingleEvent(of: .value, with: { snapshot in
let allMessages = snapshot.children.allObjects as! [DataSnapshot]
for msg in allMessages {
let msgText = msg.childSnapshot(forPath: "msg").value as? String ?? "No Msg"
let sentUid = msg.childSnapshot(forPath: "sent_uid").value as? String ?? "No sender"
print(msgText, sentUid)
}
})
}
and the output is
My message uid_1
Hello, World uid_3
another message uid_2
That being said - your structure is way to deep and should be denormalized. While it may work, as soon as you want to query for items, of find messages posted by a specific user, it just doesn't work.
I don't know your full use case but this would be a better structure
users
uid_0
name: "Hank"
uid_1
name: "Leroy"
chats
uid_0
chat_id_0: true
chat_id_1: true
uid_1
chat_id_5: true
chat_id_0
unique_id_0
msg: "My Message"
sent_uid: "uid_1"
unique_id_1
msg: "Hello, World"
sent_uid: "uid_3"
unique_id_2
msg: "another message"
sent_uid: "uid_2"
With this structure, it's all very shallow and easy to get to data - perform queries etc. You can quickly retreive all chats that uid_0 is involved with, get any messages that uid_3 ever posted or add an observer to uid_1's chat so others are notified when a chat has been added. Again, this is just an example and may not fit your case but it's something to consider.

How to find an index array inside the MongoDB document

I have one collection with this document format:
{
"_id" : ObjectId("5c51fe3a6abdf0e5cd78f658"),
"0" : {
"id" : 1,
"name" : "carlos"
},
"1" : {
"id" : 2,
"name" : "foo"
},
"2" : {
"id" : 3,
"name" : "Jhon Doe"
},
"3" : {
"id" : 4,
"name" : "Max"
}
}
the only way to access the properties was doing a foreach loop and another for in inside.
db.getCollection('tutorial').find({}).forEach( (users) => {
for(user in users){
print("ID-> " + users[user].id, " Name->" + users[user].name);
}
});
But I can only print the results, there is another way to return a value using find ?
Thanks in advance.
You have to split up your operations. Get the collection first and then run a function to return the value you wish:
let collection = db.getCollection('tutorial').find({});
let name = () => {collection.forEach( (users) => {
for(user in users){
if(users[user].name == "foo"){
return ("ID-> " + users[user].id, " Name->" + users[user].name);
}
}
})};
or simply create a variable and set it when you run the loops
let name;
db.getCollection('tutorial').find({}).forEach( (users) => {
for(user in users){
name = ("ID-> " + users[user].id, " Name->" + users[user].name);
}
});
or something similar
Though all of these scenarios seem like a strange way to handle a mongo collection. I would definitely recommend restructuring your collection if you can't access the data using regular find method.

access id of a nested document in mongoose

I want to write a put method in express for a nested document in mongoose.
I cannot access the id for the nested document.
{ "_id" : ObjectId("5b8d1ecbb745685c31ad8603"),
"name" : "abc",
"email" : "abc#gmail.com",
"projectDetails" : [
{
"technologies" : [
"abc",
"abc"
],
"_id" : ObjectId("5b8d1ecbb745685c31ad8604"),
"projectName" : "abc",
"projectDescription" : "abc",
"manager" : "abc",
"mentor" : "abc"
}
],
"__v" : 0
}
I am trying to access the id ("5b8d1ecbb745685c31ad8604") so that I can update the projectName.
I cannot think of how to write a put method for the same. Please help! Thanks in advance!!
You can use model.findOne() and then save() th update the document instead of model.findOneAndUpdate().
var projectId = "5b8d1ecbb745685c31ad8604";
var newProjectName = "def";
model.findOne({'projectDetails._id': projectId}, (err, data) => {
if (data) {
data.projectDetails.forEach((project) => {
if (project._id == projectId) {
project.projectName = newProjectName;
}
});
data.save();
} else {
// throw error message
}
})
app.put('/api/project/:id',(request,response)=>{
const projectId = request.params.id;
const projectName = "test";
db.users.update({"projectDetails._id":projectId},{$set:{"projectDetails.$.projectName":projectName}},function(err,data){
if(data){
}else{
}
})})
Instead of forEach try above query

How can I get details of single field in mongo db

I am making a web app. Currently I am storing the messages inside messages columns like below.
I have a column called msges and I have messages as time as key and value details. I want to create a function in which I pass the time, It will return the details of it. Can anyone help me? I can get single field but I don't know how to get it through key value. This is my function.
function getMessageDetails(uname,time,callback){
global.users.find({"uname" : uname,"msges":time},
// {"friends.friendUname":1,_id:0},
{_id:0},
function(err,doc){
if(err){
callback(false,err,"Message not found.",null);
}else{
callback(true,null,"",doc);
}
}
);
}
Thanks in advance. :)
I'd personally try to model your data a bit diffrently, If you had:
{
_id: "123123",
//...
friends: [
{ friendName: "etc..."}
],
msges : [
{
time: "16:25:02",
from: "alizia",
title : "hi buddy",
read: true
},
{
time: "12:25:02",
from: "bob",
title : "hi bobby",
read: false
}
]
}
You'd be able to query the following data by:
db.users.find({_id: "123123", "msges.time" : "16:25:02"}, { "msges.$.from" : 1 })
and will just pull out the one msg based on the query:
{
"_id" : "123123",
"msges" : [
{
"time" : "16:25:02",
"from" : "alizia",
"title" : "hi buddy",
"read" : true
}
]
}

Mongo nested query with keys

Need help on MongoDB nested query. Below is my mongo collection.
Preference collection
{
"_id" : "user123",
"preferences" : {
"product-1" : {
"frequency" : "Weekly",
"details" : {
"email" : {
"value" : "On"
}
}
},
"product-2" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "Off"
}
}
},
"product-3" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "On"
}
}
}
}
}
Product Collection
{
"_id" : "product-1",
"name" : "Geo-Magazine"
}
{
"_id" : "product-2",
"name" : "History-Magazine"
}
{
"_id" : "product-3",
"name" : "Science-Magazine"
}
product-1, product-2... are keys from a Map.
The keys are stored in another collection Product Collection.
Can I create a nested query to cross-reference the product keys from another table?
I need the output in the below table format. Please suggest.
user123 product-1 email On
user123 product-2 email Off
user123 product-3 email On
I tried the below but can't get result. Please suggest.
var cursor = db.productSummary.find();
while(cursor.hasNext()){
var sku = cursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "preferences."+sku+".details.email.value";
db.marketingPreferences.find( {}, {_id:1, skuCol:1, skuVal:1});
}
> var myCursor = db.productSummary.find();
> while(myCursor.hasNext()){
var sku = myCursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "$preferences."+sku+".details.email.value";
var result = db.marketingPreferences.aggregate([{"$project":{"_id":1,value:skuVal,preferences:{$literal: sku}}}],{allowDiskUse: true});
while(result.hasNext()){
printjson(result.next());
}
}
Result
{ "_id" : "user123", "preferences" : "product-1", "value" : "On" }
{ "_id" : "user123", "preferences" : "product-2", "value" : "Off" }
{ "_id" : "user123", "preferences" : "product-3", "value" : "On" }
There's a difference between MongoDB and normal SQL DB. Firstly, when you query a MongoDB collection, it doesn't return a row as it will in a SQL db. What you get here is a document similar to JSON.
Also when you use preferences.product-1.details.email : 1 it wont return you the word 'email', rather it will return you the value ie. {"value" : "On" }.
Using this: db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
you will be able to get two details which are user123 and On and you can get product-1 from your previous query. You can store these values in a variable and keep printing them to obtain the table necessary. Also you would need another cursor to store the result of the second second query that you would do.
Here's what your query will produce if it was single standalone query:
> db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
.pretty()
{
"_id": "user123",
"preferences": {
"product-1": {
"details": {
"email": {
"value": "On"
}
}
}
}
}
public static void test(){
MongoCollection<Document> collection = getDatadase().getCollection("product");
MongoCollection<Document> pref = getDatadase().getCollection("pref");
List<Document> allDocList = collection.find().into(new ArrayList<Document>());
for(Document doc:allDocList){
System.out.println(doc.get("_id"));
String preferences = doc.get("_id")+"";
String sku = "$preferences."+preferences+".details.email.value";
Document aggregation = new Document().append("$project", new Document().append("_id", 1).append("value", sku));
List<Document> pipeline = new ArrayList<Document>();
pipeline.add(aggregation);
List<Document> aggList = pref.aggregate(pipeline).into(new ArrayList<Document>());
for(Document doc1:aggList){
System.out.println(doc1.append("preferences", preferences));
}
}
}
This Will return
product-1
Document{{_id=user123, value=On, preferences=product-1}}
product-2
Document{{_id=user123, value=Off, preferences=product-2}}
product-3
Document{{_id=user123, value=On, preferences=product-3}}