local storage expiring data - javascript

I am using localStorage to save conversations client-side to save space server-side in my db. In order to do it I use an object like this:
users = {
478vh9k52k: {
name: 'john',
messages: []
},
42r66s58rs: {
name: 'jack',
messages: []
}
};
I then use users[id].messages.push(msgObj) to push new messages inside the right user ID. Lastly I use JSON.stringify and then save the resulting string.
Problem with this is that slowly the string will grow, thus filling in the limits. It is not too much of a problem the length of the messages array, because I truncate it, but the existence of old users not being necessary anymore.
Question is simple: how can I delete the old users that are contained in the 'users' object? I was thinking to add a timestamp as a key inside the object and then accessing random users to check on them at every save.
Or is there a better way to do this?

why access them randomly? you could slice up your storage in days instead, with a
localStorage["chatLogs"] = {
"13........0" : {
bob: {},
alice: {},
christoffelson: {}
}
"13....86400" : {
bob: {},
alice: {},
christoffelson: {}
}
}
and then run through your object by its keys. If they're older than a day, delete them. Alternatively, you can have a look at using indexdb instead of localStorage if you're going to do a lot of querying/filtering.

Related

How to store Object in Cookies

I have an app in Nuxt and I would like to store content of the shopping cart in the cookies. To store cookies I use cookie-universal-nuxt package. However, I am not able to store "some" objects in it. Here is an example:
const userInfo = {
name: 'Smith',
age: 41,
isVip: true,
}
this.$cookies.set('userInfo', JSON.stringify(userInfo))
console.log(this.$cookies.get('userInfo'))
This works as it should, no problem there.
Problem is, it does not work with my real objects:
const savedProductsArray = this.$store.getters['cart/products'] // returns array of products
const savedProducts = savedProductsArray[0] // select first one
this.$cookies.set('productInfo', JSON.stringify(savedProducts))
console.log(this.$cookies.get('productInfo')) // prints undefined
So the second object is apperently not stored in cookies. Any idea why? Thanks!
Btw, this is how userInfo object looks like in console:
Object {
age: 41,
name: "Smith",
isVip: true,
}
and savedProducts:
Object {
calories: 123,
name: "a",
...
}
So it looks like they are the "same" objects, but somehow only the first one can be stored in cookies...
Update: OP confirmed the issue was with cookie size.
There could be multiple issues, could you check what is the value of JSON.stringify(savedProducts) also it will help if you could include fully stringified savedProducts in the post.
Also, be aware per domain only about 4KB is allowed size for cookie so if you are trying to store that much data that could be the reason as well

Query firebase realtime database where child has property

I'm trying to query my Firebase Realtime Database to find all games a user belongs to.
I have a list of games, each game has a property of players. Each child of players has a key of $uid, and within that {key: $uid, name: "joe"}
Is it possible to get all games this way? Or do I need to start keeping another index of players_games/$uid/$game?
I've tried firebase.database().ref('games').orderByChild('players').equalTo(token.uid), but this yields null
It looks like database.ref('games').orderByChild('players/${token.uid}') works, but then I'd need to give .read access to all of games, or do this server-side.
Your current data structure makes it easy to find all the users for a specific game. It does not however make it easy to find all the games for a specific user. To allow that, you'll want to add an addition data structure that inverts the information.
So that'd look something like this:
player_games: {
"XDYNyN8il6TDsM4LuttwDzNuytj1": {
"-M5vf...U5zK": true
},
"NxH14...mxY2": {
"-M5vf...U5zK": true
}
}
Also see:
Firebase query if child of child contains a value
Firebase Query Double Nested
I recommend you also study the Firebase documentation on structuring your database, specifically the section on avoiding nested data. By mixing entity types as you currently do, you'll likely run into problems with security, and scalability.
The most idiomatic way to model your many-to-many relationship in the Firebase database is with four top-level lists:
players: {
$playerId: { ... }
}
games: {
$gameId: { ... }
}
player_games: {
$playerId: {
$gameId: true
}
}
game_players: {
$gameId: {
$playerId: true
}
}
Also see:
Many to Many relationship in Firebase

Is there any way to update a specific index from the array in Firestore

Is there any way to update a specific index from the array in Firebase/firestore?
export const editComment = (comment) => {
return (dispatch, getState, { getFirebase, getFirestore }) => {
const firestore = getFirestore();
firestore.collection('topics').doc(comment.topicId).update({
comments: <--- this is array of objects
}).then(() => {
dispatch({ type: 'EDIT_COMMENT' })
}).catch((error) => {
dispatch({ type: 'EDIT_COMMENT_ERROR', error})
})
}
}
Is there any way to update a specific index from the array in Firestore?
No, there is not! This is not possible because if you want to perform an update, you need to know the index of that particular element. When talking about Cloud Firestore arrays, the things are different that you might think.
Because we are creating apps that can be used in a multi user environment, try to think what might happen if a user wants to edit a value at index 0, some other user wants to delete the value at index 0 and in the same time some other user might want to add another item at index 0. For sure, you'll end up having very different results and why not, get even array out of bounds exception. So Firestore actions with arrays are a little bit different. So you cannot perform actions like, insert, update or delete at a specific index.
If those two methods do not help you enough, you should get the entire document, get the array, modify it and add it back to the database.
Turn the array into it's own separate document and update the field in there. That's what I did. I had to restructure my database a bit in order to do so.
for me, I'm using firebase SDK for flutter, and nodeJS env. for cloud functions,, and I discovered the below solution.
this is a little bit of a hacky workaround
maybe we can save the list in a form of map not an array,, by using the array indexes as key strings to the sub maps
so you have structured the data like this in cloud fire store
key1: "value1" --> string
key2: --> map
> "0": {subKey1: "subValue1", subKey2: "subValue2"}
> "1": {subKey3: "subValue3", subKey4: "subValue4"}
> "2": {subKey5: "subValue5", subKey6: "subValue6"}
for example : if you want to update the subValue4, you may do this
await docReference.update({key2.1.subKey4: "theNewValueHere"});
and this ends up updating that document in cloud firestore to a document that looks like this
key1: "value1" --> string
key2: --> map
> "0": {subKey1: "subValue1", subKey2: "subValue2"}
> "1": {subKey3: "subValue3", subKey4: "theNewValueHere"}
> "2": {subKey5: "subValue5", subKey6: "subValue6"}
if you notice in firebase,, it updates the entire field key2 in this operation,, but gave you an easier access to update that index..
My problem is that I have to restructure all fields having list of maps to become maps within a map to have that access
And I will not do that,, will not refactor my entire db to do that,, I retrieve the entire doc,, (costs 1 read) modify at client and update the entire doc again (1 write)
I don't like it, but maybe someday I would use it

Sort list of ID by ID child in another node in Firebase

I building react-native chatroom feature by using Firebase. I would like to sort the chatList according to the lastMessage createdAt value in another collection.
Here is the sample structure of my current structure chat:
{
Chatrooms: {
CHAT_ID_1: {
messages: [...],
metadata: {
lastMessages: {
createdAt: 1515857717832 //the time
},
users: [USER_ID_1, USER_ID_2]
}
},
CHAT_ID_2: {
messages: [...],
metadata: {
lastMessages: {
createdAt: 1515857717834 //the time
},
users: [USER_ID_1, USER_ID_3]
}
}
},
Users: {
USER_ID_1: {
chatList: {
USER_ID_3: CHAT_ID_2,
USER_ID_2: CHAT_ID_1,
}
}
}
}
Since the CHAT_ID_2 has the latest lastMessage createdAt time, it should be the first one in the chatList of USER_ID_1.
I would like to know how to sort this.
From what I see there is no way to do a query that gets you the chat rooms that a specific user is in order by last update timestamp.
Solutions I can quickly think of:
Load the last update timestamp for each room the user is in with a separate call, and then order them client-side.
Store the last update timestamp for each chat room for each user and then do a query.
I hope the first solution is self-explanatory. While it does require some extra code, it's actually a lot more efficient than most developers think because the calls from the client to the database are pipelined over the same connection.
The second solution is to add additional data to /Users/$uid/$chatroomid to suit your use-case. So for example:
Users: {
USER_ID_1: {
chatList: {
CHAT_ID_2: 1515857717834
CHAT_ID_1: 1515857717832
}
}
}
With this structure you can get the chats in order of most recent update with:
firebase.database().ref("Users/USER_ID_1/chatList").orderByValue()
But in this case I'd go for option 1 myself. Since the number of chat rooms for each user is likely to be fairly small and the loads don't require queries, it's likely to both perform and scale well.

Smart way to push object to firebase

I have an object that I want to push to the firebase realtime database, looking like this:
userProfile = { name: "Jon", age: 25, gender: "male", ...plenty more attributes}
If I want it in firebase, I could write it like this:
return firebase.database().ref('/userProfile').push({
name: userProfile.name,
age: userProfile.age,
gender: userProfile.gender,
....
}).
But since I have plenty of objects with many attributes I would prefer not writing it by hand. Loops are not allowed in push (). I could push the whole object like this:
return firebase.database().ref('/userProfile').push({
userProfile: userProfile
}).
But it will create an additional child node like
ref/userProfile/123someId/userProfile/name
which is bad practise because it disallows using filters and more later on.
Is there a more effective way to push the attributes of an entire object without writing down every key/value pair?
The answer could not be easier, but in case someone else stumbles across the same issue:
firebase.database().ref('/userProfile').push(userProfile)
Thanks guys

Categories