create mongodb list inside of a table - mongodb

I want to create a chat app.
I need to decide how my DB is gonna look like.
I a m using mongodb as a DB.
I want to have a collection named "users" which will have every user that is registered for my app.
i.e.
users
- Mike
- David
- Adam
I also want to have a collection of rooms that are in my chat app.
i.e.
rooms
- Game of thrones
- Class of 94'
- sicence fiction
- pet lovers
I also want to have a collection of room with users
i.e.
pet lovers (room name)
- Mike (user1)
- Dave (user2)
.....
I know how to represent the users and rooms in mongodb.
But any idea how to represent the "users in room" collection? it seem I need a list inside a collection (list of users in room) in addition I need to save the room name.
I want it to be easy to pull data out of this collection (i.e. remove or add user to a room / find out which room a user is chatting in...)
also, if someone has a better suggestion to represent this data - feel free...
Thanks

you can add a users array that contains IDs of users in a given room to room document, so the rooms collection will something looks like:
[
{
"_id":"...",
"roomName":"Game of Thrones",
//...
"users":[
"userId1",
"userId2",
//...
"userIdn"
]
}, {
"_id":"...",
"roomName":"the secret zone",
//...
"users":[
"userId2",
//...
]
}
]
then, when a user join a room R, you'll add his ID to R.users array. and remove it when he left.
by the way, I think defining some schema model with mongoose may be helpful

Related

How correctly aggregate and lookup mongo data to models

Consider two collections:
users (can be both, organizer and participant in other meetings)
meetings
For the sake of simplicity, I show here only the basic data, in my code i have emails, passwords, etc.
User (easier part)
{ "_id": "ObjectId('user0_id')", "username": "Paul" }
and model:
type User struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Username string `json:"username"`
}
Meeting:
{
"_id": "ObjectId('meeting0_id')",
"organizer": "ObjectId('user0_id')",
"participants": [ "ObjectId('user1_id')", "ObjectId('user2_id')", "ObjectId('user3_id')"]
}
and model:
type Meeting struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Organizer primitive.ObjectID `json:"organizer"`
Participants []primitive.ObjectID `json:"participants,omitempty"
}
Everything works if I extract only the basic data from mongo, but it seems ineffective... Because if I want to present this data in a readable form, I can't use only ObjectID, but with mongo "$lookup" I would like to get more data about users right away.
Another problem, in some cases I need a different dataset. Once to show a list I need only
the name of the users assigned to the meeting.
However, in the case of data administration or sending notifications, I need more (all?) User data.
How to correctly (what are the best practices) to store data like this in Go models?
Create one super-struct "meeting" with all possible data? Eg.with Participants []User instead of ID's ?
But what next? Get a complete set of data from the database each time, then filter it on the code side? Or filter on mongo side, but in most cases almost all fields in struct will be empty (eg. LastPasswordChangeDate in simple meeting participants list). Especially since there may be more "lookup" data, e.g. meeting place, invitations, etc., etc.
How finally save this super struct to two collections?
P.S. Create different models for different "views" of meetings seems super stupid...

Mongo: Two collections with pagination (in single list in html)

Currently in our system we have two separate collections, of invites, and users. So we can send an invite to someone, and that invite will have some information attached to it and is stored in the invites collection. If the user registers his account information is stored in the users collection.
Not every user has to have an invite, and not every invite has to have a user. We check if a user has an invite (or visa versa) on the email address, which in those case is stored in both collections.
Originally in our dashboard we have had a user overview, in which there is a page where you can see the current users and paginate between them.
Now we want to have one single page (and single table) in which we can view both the invites and the users and paginate through them.
Lets say our data looks like this:
invites: [
{ _id: "5af42e75583c25300caf5e5b", email: "john#doe.com", name: "John" },
{ _id: "53fbd269bde85f02007023a1", email: "jane#doe.com", name: "Jane" },
...
]
users: [
{ _id: "53fe288be081540200733892", email: "john#doe.com", firstName: "John" },
{ _id: "53fd103de08154020073388d", email: "steve#doe.com", firstName: "Steve" },
...
]
Points to note.
Some users can be matched with an invite based on the email (but that is not required)
Some invites never register
The field names are not always exactly the same
Is it possible to make a paginated list of all emails and sort on them? So if there is an email that starts with an a in collection invites, that is picked before the email that starts with a b in collection users etc. And then use offset / limit to paginate through it.
Basically, I want to "merge" the two collections in something that would be akin to a MySQL view and be able to query on that as if the entire thing was one collection.
I'm preferably looking for a solution without changing the data structure in the collection (as a projected view or something, that is fine). But parts of the code already rely on the given structure. Which in light of this new requirement might not be the best approach.

Designing mongo 'schema' for RESTful application

I'm trying to teach myself mongo through writing an application, and I'm struggling with the best way to design the mongo 'schema' (I know it's schemaless, but that is probably the core issue with my understanding in that I'm coming from a relational background)
Anyway, the application is a Gift List manager, where a user can create a Gift List and can add Gifts they would like to receive to their list. Other users can subscribe to the list, and can mark a Gift from the Gift List as claimed/purchased. (So as to prevent the problem of getting duplicate gifts at Christmas!)
At the moment my GiftLists collection is not 'relational' and is simply a collection of GiftList documents with sub documents for the Gifts, like this:
{
"GiftLists": [
{
"_id": {
"$oid": "55e9924848c4ffd723890b48"
},
"description": "Xmas List for Some User",
"gifts": [{
"description": "Mongo book"
"claimed": false
},
{
"description": "New socks"
"claimed": false
},
{
"description": "New socks"
"claimed": false
}],
"owner": "some.user",
"subscribers": ["some.other.user", "my.friend"]
}
]
}
The idea is that some.user is the owner of the Gift List and has added 3 items he would like to receive. some.other.user has subscribed to the list and can see the Gift List and it's Gifts. He may choose to buy one of the gifts, so needs to mark it as claimed so that my.friend does not also buy it.
At the moment, each Gift in the gifts array is a sub-document without its own id, and I think this is where I'm getting stuck in my understanding/thinking.
I'm trying to provide the app functionality with a RESTful interface.
To POST a new Gift List the url is /giftList/add where the request body is the new Gift List
To GET an individual Gift List including the child Gift's the url is /giftList/<listId> - eg: /giftList/55e9924848c4ffd723890b48
With the above in mind, my natural next step is to be able to mark a Gift as claimed, perhaps with:
PUT to the url /gift/claim/<giftId>
But I don't have any ids on the Gift sub documents
So maybe my url should be:
/giftList/<listId>/claim/<giftId>
But again, I don't have an id on the Gift sub document
Or maybe I try to use the description of the item
/gift/claim/<gift description> eg: /gift/claim/Mongo+book
But what if more than one person had a Gift List containing 'Mongo book', and URL encoding the characters of the description could be messy
Or maybe I reference the Gift List
/giftList/<listId>/claim/<gift description> eg: /giftList/55e9924848c4ffd723890b48/claim/New+socks
But which instance of 'New socks' am I claiming? (after all, everyone needs lots of new socks for Christmas!)
Or maybe I reference the index of the Gift
/giftList/<listId>/claim/<gift index> eg: /giftList/55e9924848c4ffd723890b48/claim/2
But this feels fragile (as it implies that the list must always be presented in the same sequence)
To me what it really feels like is that I need another collection, just for the Gifts, where each Gift document has its own id, which I can then reference in my RESTful url. And either the Gift has a reference to it's parent GiftList, or the GiftList has an array of references to the Gifts
But this is all a very 'relational' way of thinking ... isn't it ?
What's the best way of doing this? Or, if there is no 'best' way, what are my options?
You could solve this with a new collection, or you could add an unique identifier field to each list entry. The MongoDB solution for unique identifiers is generating an ObjectId, just like those used for the _id field of documents. Most MongoDB database drivers should expose functionality for generating ObjectId's. For details, consult the documentation of your database driver.

mongodb - proper way of data modeling

I have a collection that represents users, with their names and roles, where a role can be admin, user or guest (lets assume one role per user). Basically I'm new to mongodb. What I would do in a relational database is keep two linked tables, one for users and one for roles. I'm not sure what is the best way to handle this in mongodb though. For instance, should my collection look like so?
{ {"name": "John", role: "admin"}, {"name": "Jack", role: "user"} }
In this case, if I have a typo in one of the roles, then I would have to update all the users with that role. What scheme would you suggest?
Yes, it's the best way to do it and you're right if you want to change a role name you have to update all the item in the collection but it's a single command.
The benefit would be also to have several roles for a single user with requiring to add a table, like this:
{ {"name": "John", roles: ["admin","user"]}, {"name": "Jack", roles: ["user"]} }
But if the role part start to grow, with some access right, having the possibility to share the same right between users, etc.. you can also create a second table with roles, and juste reference the id in the user table, just like a join in SQL
#tomsoft's solution is great.
I give you my piece of advice: when you have a multiple enumerate, traduce "enumerate" like a list. Its much easier for me do this.
Another example:
Vehicles is an enumerate: you can have motorbike, scooter, car, truck...
But you must be wary with atomic enumerates, like favourite fruit:
[Banana, Apple, Peach, Grape] You only must to choose one!

Ideas how to query two collections in mongodb

I have collection friends
- userId: user id
- Friends: array of user ids
And users
- _id: userId
- Last Login
- Other User info fields
Last login field is updated every 5 minutes if user is browsing my website.
Right now I have logic where I get user ids from friends from friend collection, then query user collection with that ids to get user info.
ADDED: In addition in future releases i would add that user will be able to add friends not only users but pets from other collection so friend embedded array will look like {UserId, PetId}
But for next release I would like to add new functionality where I would show friends sorted by last login.
Solutions which I think would work
Map reduce on select -Easy to implement but would probably have problems with performance
Map reduce on update - in this case i would probably use property "out" to write new collection on each update, so then i will have new collection Friend.reduced with all info i need, and then i can easy query it by indexes
Add new property Last Update to Friends list collection so it will look like {FriendId, LastUpdate} logic would be easy to implement on Business level.
What other options to solve my issue?
And simple query like below won't work?
var someId = ObjectId("52758653cbd6ca816ca0ee1b")
var friends = db.friends.findOne({"userId": someId}, {"_id": 0, "friends": 1}).friends
db.users.find(
{_id: {$in: friends }}
).sort({lastLogin: -1})