-
Notifications
You must be signed in to change notification settings - Fork 0
Topic: Relational NoSQL Database
MongoDB is a NoSQL database consisting of documents. This document architecture works much like JavaScript Object Notation (JSON), in the sense that everything is an object, nested in another object.
Say I have a user in my database. That will look like this:
As you can see, this user document consist of nested objects. These exist only within this document, in this collection of the database. A collection within MongoDB is essentially an array of documents, or a folder, if you prefer that analogy.
The problem with this folder-like structure as compared to a regular SQL database, is that documents share no relation to other documents. For example, I can't query the name of the users in this user's liked array, because they share no relation.
In my server-side code, I've made two kinds of relations between different documents in different collections.
When you like a user, a reference to their unique ObjectID is stores in an array. This object ID mirrors a user ID in the app.
When I want to get information on a specific user I've liked, I can simply query their ObjectID, as referenced in my liked array. This will in turn give me back their document, with every bit of data they have stored.
This one is a bit more involved. In the app, users are able to start private chats only they and one match can see. This is private messaging between two persons. As you can see by looking at the document up top, no reference is stored to the chat messages this user has sent or the chats they are a part of.
Since users need to be able to chat one-on-one with their possible next love, we create private rooms for them to discuss whatever they like. These rooms are stored as documents in the chats collection of our database. A chat document looks like this:
{
"_id": "5ee252b039426f1c9ae0ae0f5ee25d2fbb19421ed9cdf279",
"messages": [...]
}Lets start at the ID. As you may notice, this ID is a lot longer than a regular document ID, as discussed earlier. The main key to these private chatrooms is this ID. When starting a chat with someone, an ID is generated based on your user ID and your participant's user ID.
The private room key is composed in the following manner:
const roomId = [req.session.user._id, req.params.userId]
.sort()
.toString()
.replace(',', '');req.session.user._id is your unique document ID, and req.params.userId is your participant's ID. These two values are sorted alphabetically with .sort(), then turned into one longer string.
This also gives us a security benefit. Since chats are requested based on your user ID while you are logged in, you're only ever able to access the chats that belong to you. This also means nobody can act like they're you and read your chats unless they know your login credentials.
So now we've generated a private room key based on the IDs of two users. On to the next step.
When a user logs in, and navigates to their chat screen, they will see the messages they've sent and received. However, it would be nice if we could tell who sent which message. This is solved by giving the sender's user ID with the message data to the chat docuent.
{
"_id": "5ee25d2fbb19421ed9cdf2795ee25d2fbb19421ed9cdf279",
"messages": [
{
"message": "Hey there",
"userId": "5ee25d2fbb19421ed9cdf279"
},
{
"message": "You seem fun to be around :)",
"userId": "5ee25d2fbb19421ed9cdf279"
},
{
"message": "...hello?",
"userId": "5ee25d2fbb19421ed9cdf279"
}
]
}Each message in the messages array holds the content of the chat message and its sender's user ID. This way, when we request the data, we will be able to see who sent what. This user ID is then used to query the users collection to fetch data like their first and last name. This is also how chats are made visually distinguishable without CSS. Without CSS, messages are prepended with the sender's name. For more information, please see my article on how I implemented progressive enhancement within the app.
Even though MongoDB does not serve a relational architecture in its NoSQL database, I've been able to implement some relational behaviour by sending along references to other documents. All that was left to do is the query those documents when their respective data is needed. Et voilà, relational database behaviour in a non-relational database!
Didier Catz
{ "_id": { "$oid": "5ee252b039426f1c9ae0ae0f" }, "email": "test@test.com", "firstName": "Joris", "lastName": "User", "age": "22", "gender": "m", "pass": "$2b$10$anFvirkGOj0Kr4JmnqSK7utK7QUJTMi7W2gHNap/9icsbUtO7mPFe", // encrypted hash "liked": ["5ee25d2fbb19421ed9cdf279"], "disliked": [], "filter": { "orientation": "f", "maxAge": 27 }, "bio": "Hey! I like skateboarding and going out to eat. In my free time, I play guitar.", "interest": ["Football", "Music", "Food"] }