Flutter Firestore understanding joins - firebase

I am doing this in Flutter, with a Firebase database, using the Firestore packages in Flutter. I would like to know how a join is done in noSQL (or more specifically, in Flutter-Firestore)
This is what my database looks like:
users: {
U1: {
name: 'Peter',
surname: 'Jensen'
},
U2: {
name: 'Marry',
surname: 'Kown'
},
...
}
groups: {
G1: {
name: 'Group 1'
},
G2: {
name: 'Group 2'
},
...
}
members: {
M1: {
userId: U1,
groupId: G1
},
M2: {
userId: U1,
groupId: G2
},
M3: {
userId: U2,
groupId: G1
},
...
}
Now how do I do a join to get something like this:
members: {
M1: {
userId: {
name: 'Peter',
surname: 'Jensen'
},
groupId: {
name: 'Group 1'
}
},
M2: {
userId: {
name: 'Peter',
surname: 'Jensen'
},
groupId: {
name: 'Group 2'
}
},
M3: {
userId: {
name: 'Marry',
surname: 'Kown'
},
groupId: {
name: 'Group 1'
}
},
...
}
Do I do:
const users = await Firestore.instance.collection('users').getDocuments();
const groups = await Firestore.instance.collection('groups').getDocuments();
const members = await Firestore.instance.collection('members').getDocuments();
...manually loop through everything and assign everything myself
(I need to add more text because I have 'mostly code'): I would assume the above would use of a lot of query data in Firebase, so I can't see how this would be a good idea. I actually just want to see in what groups is a user a in

If you have groups and members, I'd typically store the follow data:
A list of users in a users collection.
For each user I'd keep their properties and a list of the group IDs of the groups they're a member of.
A list of groups in a groups collection.
For each group I'd keep their properties
Note that you could model the nested list as a subcollection, but typically this is not needed. With the above model you can easily find what groups a user is part of, even even do a query for users who are part of a certain group with an array-contains clause.
To get a list of the properties of the group for a specific user, you'll indeed need to load that user, and their groups separately. This is normal with many NoSQL databases, and not necessarily as slow as you may expect. But if performance is not good enough, you can consider duplicating some data to reduce the need for joins. It all depends on your needs, and unlike in relational data models, NoSQL is not dogmatic about such things.
To learn more about this topic:
read NoSQL data modeling
watch Getting to know Cloud Firestore

Related

How to check if an entry already exists when posting in Dynamo DB with AWS Amplify

In an Amplify w/ graphql project, I have a conversation schema which both members of the conversation saved in an array. When creating a conversation, I only want one conversation to exists between two users. So I want the creating of the conversation entry to fail when a conversation already exists.
When creating the mutation, I tried to use the condition input to let the query fail when the condition is false. But I have not found a solution to check the members array.
Any advice on using the conditions input is appreciated!
type Conversation
#model {
id: ID!
members: [String!]!
...
}
const createConversationInput: CreateConversationInput = {
members: [userOneId, userTwoId],
...
};
const createConversationMutation = (await API.graphql({
query: createConversation,
variables: {
input: createConversationInput,
condition: {
and: [
{ not: { members: { contains: userOneId } } },
{ not: { members: { contains: userTwoId } } },
],
},
},
...
})) as { data: CreateConversationMutation };

firebase work with the user nick name or the user id?

I'm new in firebase, I know in mysql we have a table users with a unique id (eg: 1, 2...).
If I have a table follow and I want to record who follows who, I add:
follow
1 3 // user_id 1 follows user_id 3
3 2
3 1
I'd like the best approuch in firebase real time database, I have a json users, with unique key too and username. And I have json follow:
follow:
CMypCAlwMXPeM8X07P0sKsO
|
--- randomkey
|
--- follow: UFPRK8GG4tMvCejEfqWiCE220Mv2
in other words, user CMypCAlwMXPeM8X07P0sKsO follow user UFPRK8GG4tMvCejEfqWiCE220Mv2.
In firebase, should I work with this unique users keys (like mysql) or should I use usernames? like:
josh
|
... randomkey
|
--- follow: marie
thanks!
To model followers between users in Firebase Realtime Database, I typically end up with three top-level lists:
users: {
uid1: { ... },
uid2: { ... },
uid3: { ... }
},
followers: {
uid1: {
uid2: true
},
uid2: {
uid3: true,
},
uid3: {
uid1: true
}
},
followees: {
uid1: {
uid3: true
},
uid2: {
uid1: true,
},
uid3: {
uid2: true
}
}
So you're essentially splitting your single follow table into two top-level lists: one for each "direction" of the relationship.
Also see:
Many to Many relationship in Firebase
Firebase simple many to many relationship

Firebase data modeling for inequality check

i've been developing a mobile app with react native & firebase realtime db, and i'm stuck with a data-modeling problem.
My app will let users to vote photos that uploaded by other users and each user will be allowed to vote once for each photo. I'm providing a tinder-like UI for voting action. I'm planning to have users and photos trees on the firebase looks like this, which is pretty straight forward:
{
users:{
userId1: {
name:'John'
surname: 'Doe',
votedPhotos: {
somePhotoId: {
timestamp: 1528836856000
},
somePhotoId2: {
timestamp: 1529363754000
},
...
},
...
},
userId2: {
name:'Johnny'
surname: 'Doerr'
...
},
...
},
photos: {
photoId1: {
url: 'https://a-firebase-storage-url',
owner: {
uid: 'userId1',
fullName: 'John Doe'
},
upvoteCount: 12,
downvoteCount: 8
},
photoId2: {
url: 'https://another-firebase-storage-url',
owner: {
uid: 'userId2',
fullName: 'Johnny Doerr'
},
upvoteCount: 28,
downvoteCount: 4
},
...
}
}
I need to prevent users to vote their own photos and vote a photo more than once. So i need to query photos as excluding already voted photos and self uploaded photos for a user. If i was using a traditional db it would be easy as a pie but i couldn't figure out how to do that query in a firebase realtime database since i can't use not_equals or not_in. How would you suggest me to model my data?
Record user votes under the photouid. I imagine a .length could provide you the total votes.
photos
photo1-uid
owner:user1-uid
votes:{
user2-uid: true,
user3-uid: true
}

Getting 'query in command must target a single shard'

I have a CosmosDB setup using the Mongo API. I have a collection with a hashed shard on one of the field of the document. When I run commands like db.collection.remove or db.collection.deleteMany I get the following error.
Command deleteMany failed: query in command must target a single shard key.: {"message":"Command deleteMany failed: query in command must target a single shard key."}
I'm not sure how can I mention a shard key as part of the query considering I want the query to run across all the shards.
You need to provide shard key when you want to run commands like db.collection.remove or db.collection.deleteMany.
For example :
My data source as below:
[
{
"id" : "2",
"name" : "b"
},
{
"id" : "1",
"name" : "a"
}
]
And my shared key is "/name". Use db.coll.deleteMany({"name":"a"}) to delete specific shard.
Hope it helps you.
It should be ShardKey which you have chosen when you created cosmosDb collection.
FilterDefinition<Product> filter = Builders<Product>.Filter.Eq("id", 2);
=== 2 is my shardKey
await this._dbContext.GetProducts.DeleteOneAsync(filter);
return RedirectToAction("Index");
Kindly refer an image below , how does it look like in CosmosDB
Shard Key(Partition Key) has to be provided during specification of schema model in the code. Once its provided, we can perform regular operation like save, update and delete as usual.
Example:
const mySchema = new Schema({
requestId: { type: String, required: true },
data: String,
documents: [{ docId: String, name: String, attachedBy: String }],
updatedBy: {
type: {
name: { type: String, required: true },
email: { type: String, required: true },
}, required: true
},
createdDate: { type: Date, required: true },
updatedDate: { type: Date },
}, { shardKey: { requestId: 1 } }
);
In the above code we specified requestId as Shard Key, now we can perform any mongo operations
Example:
let request:any = await myModel.findById(requestId);
request.data ="New Data";
await request.save();
Hope that helps.
This works with all Mongo operations

Firebase notEqualTo alternative in schema

I am creating app using Firebase database. This app is very similar to Tinder. You simply rate profiles and I need to query database for profile that user doesn't rated yet. My schema looks like this:
{
users: {
user1: {
alreadyRated: {user2: true, user3: true}
},
user2: {
alreadyRated: {user1: true}
}
},
userProfiles: {
user1: {
name: "John",
age: 20,
...
},
user2: {
name: "Jane",
age: 30,
...
}
}
}
So, if I am user2 I want get all profiles that I doesn't rated yet, in my example I want user3 profile. How to do that? Now I am downloading all profiles and filtering it on client side, but it's not good solution, because there could be hundred or thousands profiles in future. I think I should change my database schema, but I don't know how.
Thank you for ideas.

Resources