I have a small realtime firebase database that's set up like this:
database
-messages
--XXXXXXXXXXXX
---id : "XXX-XXX"
---content : "Hello world!"
It's a very simple message system, the id field is basically a combination of users id from my mysql database. I'm trying to return all messages that match one of the ids, either sender or receiver. But I can't do it, seems like firebase only support exacts querys. Could you give me some guidanse?
Here's the code I'm working with
firebase.database().ref("messages").orderByChild("id").equalTo(userId).on("value", function(snapshot)
I'm looking for something like ".contains(userId)"
Firebase supports exact matches (with equalTo) and so-called prefix queries where the value starts with a certain value (by combining startAt and endAt). It does not support querying for values that end with a certain value.
I recommend keeping a mapping from each user IDs to their messages nodes, somewhere separately in their database.
So say that you have:
messages: {
"XXXXXXXXXXXX": {
id : "YYY-ZZZ",
content : "Hello world!"
}
}
You also have the following mappings:
userMessages: {
"YYY": {
"XXXXXXXXXXXX": true
},
"ZZZ": {
"XXXXXXXXXXXX": true
}
}
Now with this information you can look up the messages for each user based on their ID.
For more on the modeling of this type of data, I recommend:
Best way to manage Chat channels in Firebase
Many to Many relationship in Firebase
this artcle on NoSQL data modeling
Related
I have a real time firebase app with chatrooms and comments. A comment belongs to a single chatroom and a chatroom can have many comments. I'd like retrieve just the comments for a given room, but right now I'm only able to get all of them.
Every time a comment is saved, I also save its id to the room to which it belongs. That way, every room has a list of its comment ids. I can retrieve a chatroom's list of child comment ids using chatRooms/${id}/commentIds.
// data structure is basically like this:
chatRooms: {
ROOMID123: {
title: "Room A",
commentIds: {
COMMENTIDABC: true,
COMMENTIDXYZ: true
}
}
},
comments: {
COMMENTIDABC: {
message: "some message",
parentRoomId: ROOMID123
},
COMMENTIDXYZ: {
message: "Another message",
parentRoomId: ROOMID123
}
}
I can get the comment ids for a given room, based on the room's id, like this:
firebase.database().ref(`chatRooms/${chatRoomId}/commentIds`).on('value',
snapshot => {
const commentsObject = snapshot.val();
const commentIdsList = Object.keys(commentsObject);
});
Would it be better for me to
a) use that list of commentIds to retrieve only the comments for a given room? If so, what query should I use?
b) use the chatRoom's id to retrieve every comment with a matching parentRoomId? If so, I don't know how to do this despite reading through the docs.
Thank you!
I'd propose a third option: store the comments for each chat room in a separate parent node. So something like:
commentsPerRoom: {
ROOMID123: {
COMMENTIDABC: {
message: "some message",
},
COMMENTIDXYZ: {
message: "Another message",
}
}
}
With the above structure you can retrieve the comments for a specific room with a single direct lookup:
firebase.database().ref(`commentsPerRoom/${chatRoomId}`).on('value',
Reasons I'd use this data structure over your current one:
Storing the comments as a single list means you'd have to query that list. And while Firebase Realtime Database scales quite well, querying for data is always going to have scalability limits. That's why the above data structure allows a direct look up, instead of requiring a query.
Loading the individual comments through the comment IDs is definitely also possible, and not nearly as slow as some developers think due to the fact that Firebase pipelines the requests over a single connection. But it seems unneeded here, since the comments already have a strong 1:n association with the room they belong to. Each comment only belongs to one room, so you might as well model that relationship in how you structure the data, and save yourself all the lookups.
Retrieving comments for a specific room is by far the most common use-case, and this data structure allows that use-case the most efficiently.
I have my current Discord Bot project using JavaScript however i cannot find a way to store the value itself when done through a command such as !setname ___ hoping for a response of that being repeated back when I use !myname.
I know how to do it by storing it temporarily through:
bot.on('message', function (user, userID, channelID, message, evt) {
if(message == "!myname") {
bot.sendMessage({
to: channelID,
message: 'Your name is ' + user.username;
});
}
}
However i cant figure out how to do it through the ability to call for it whenever you want rather than getting an immediate response. For example setting my name now but being able to have it output when i use the command instead of having command that sets the value then outputs it in an immediate string
Would recommend a simple key-value dictionary style in the current instance.
(Though you could store it to a text-file or database later if you prefer the data to be persistent across different sessions.)
Instance based:
Based on this post on stackoverflow...
You can create a global dictionary at the top var usernameChangeDict = {};
Whenever the user invokes !setname, just do:
usernameChangeDict[user.id] = Their_new_name_here
Fetch it back using usernameChangeDict[user.id], should return null or empty if they did not set their name before.
Persistent data:
Could either store it in a text file on your local computer, or do a database as Zooly mentioned.(Though personally, a database would be an overkill if your bot is not going to be used by a wide range of people.)
Text file
Read from this post, it contains details on how to write onto a text file.
This post talks about reading from a text file.
I would recommend storing it in a JSON format to make your life easier, since JSON.parse exists.
Most likely you would end up storing in a format like this:
{ "23125167744": "someone", "USER_ID": "username" }
Access it by parsedJson["USER_ID"].
SQLite
This tutorial would probably explain how to set your SQLite for javascript better than I do.
Once its all setup, just store the userID and username, you can just do:
SELECT username FROM yourTable WHERE userID = ?;
and
INSERT INTO yourTable (username, userID) VALUES (?, ?);
For inserting and selecting into database respectively.
I am looking for a generic way to pass any query string (from any oracle table, NOT hardcoded) from a webpage form/field to database and make the webpage display table/grid of the results. All examples i have seen so far require hardcoding columns/table name upfront in CRUD apps on github. I would like to be able to get results from various tables each with different columns, data types. I dont want the tables/columns hardcoded in the app. I have been using SpringBoot so far to accept any query string in POST req and return results as list of json records but i want to make it more interactive, easy to use for casual users so seeking some examples for simple textfield input and dynamic results grid.
Have a look at Knex.js: https://knexjs.org/
It's a query builder that works with different databases. Here's a little sample from their doc:
var knex = require('knex')({
client: 'oracle'
});
function handleRequest(req, res, next) {
query = knex.select(req.body.columns).from(req.body.table);
console.log(query.toString()); // select "c1", "c2", "c3" from "some_table"
}
// Imagine this was invoked from Express and the body was already parsed.
handleRequest({
body: {
table: 'some_table',
columns: ['c1', 'c2', 'c3']
}
});
As you can see, the inputs are just strings which can come from anywhere, including clients/end-users. Just be careful that the user that's connecting to the database has the appropriate grants (least privilege applies here).
I'm doing a academic project. simply the idea is creating an Attendance system that goes like this:
The Teacher logs in to his account in the website.
Teacher selects a section.
Teacher generates a QR Code to let the students scan it to attend.
The Student Sign in into his account using an android app.
Students Opens the scanner to scan the QR Code.
The system marks the attendance of that student in that specific section and in a specific date.
here is my design of the firebase database that i'm using
db{
Teachers{
"cEEbohuR2bK6opZJ1z5RoPrbbrx1":{ //auth uid
tchName:"Jason",
tchID:"24123"
}
Students:{
"GsBEVEtZ9CeqzztDWEQd9GluVJJ3":{ //auth uid
studentName:"Mark",
stuID:"37294"
}
Courses:{
"JAVA101":{ //courseID
courseName:"Java Programing",
}
Sections:{
"56345":{ //secID
tchID:"24123", //acts like a foreign key
courseID:"JAVA101", //acts like a foreign key
Students:{
"37294":{
studentName:"Mark"
}
}
}
Attendance:{
"56345":{ //secID
"1-8-2018":{ //auto generated date?
"37294":{ //stuID
attended:"true" // sets to true after scanning the qr code
}
}
}
}
}
My idea of the qr code thing is when the teacher generates it the value in the QR would be the Section ID then somehow I need to merge it with student ID when the student scans it, after getting the two values I need to auto generate the date of the lecture
,so i would have 3 values(secID,stuID,date) to insert it into the Attendance tree and make the "attended" attribute sets to "true"
Now my questions are:
is there any better way to design my DB?
is my qr idea above possible to execute or is there a better way?
Do you need the instructor to retrieve the attendance list? The nested object you show above could be flatter if your needs were different. In Firebase, you need to create your DB structure after your views (e.g., what you will retrieve from DB to show to users). Nesting is strongly discouraged against and duplication of data is acceptable.
For example if I wanted users to read the list of attendees by choosing a section ID and date, I would create a table like this:
Attendance:{
"123456": //section ID
{"01-08-2019": //date
{"865768": true} //student ID: attendance status
}
}
I can retrieve the list of attendees using the reference:
`Attendance/${sectionID}/${date}/`
Or I can have a flatter list if I wanted my users to click on a student's ID and retrieve all attendance records by the student:
AttendanceRecord: {
"865768": { //student ID
"LxLy1a": { //unique attendance record key
date: "01-08-2019",
sectionId: "123456",
status: true
}
}
If my app's views were different, I would have to structure my database differently so that data is easier to read from Firebase without going too deep into the nested object.
You must not be too afraid to duplicate your data. Change your database based on the views in your app.
In my user collection, I have an object that contains an array of contacts.
The object definition is below.
How can this entire object, with the full array of contacts, be written to the user database in Meteor from the server, ideally in a single command?
I have spent considerable time reading the mongo docs and meteor docs, but can't get this to work.
I have also tried a large number of different commands and approaches using both the whole object and iterating through the component parts to try to achieve this, unsuccessfully. Here is an (unsuccessful) example that attempts to write the entire contacts object using $set:
Meteor.users.update({ _id: this.userId }, {$set: { 'Contacts': contacts}});
Thank you.
Object definition (this is a field within the user collection):
"Contacts" : {
"contactInfo" : [
{
"phoneMobile" : "1234567890",
"lastName" : "Johnny"
"firstName" : "Appleseed"
}
]
}
This update should absolutely work. What I suspect is happening is that you're not publishing the Contacts data back to the client because Meteor doesn't publish every key in the current user document automatically. So your update is working and saving data to mongo but you're not seeing it back on the client. You can check this by doing meteor mongo on the command line then inspecting the user document in question.
Try:
server:
Meteor.publish('me',function(){
if (this.userId) return Meteor.users.find(this.userId, { fields: { profile: 1, Contacts: 1 }});
this.ready();
});
client:
Meteor.subscribe('me');
The command above is correct. The issue is schema verification. Simple Schema was defeating the ability to write to the database while running 'in the background'. It doesn't produce an error, it just fails to produce the expected outcome.