MongoDB design for multiple auth user accounts - node.js

I have a backend with nodeJS, Express and MongoDB / mongoose...
My users can signUp/Login with Google or email and password. But now my question is what's the best option of building a model for that.
My first option is this:
{
firstname: myname,
lastname: mylastname',
email: 'email#example.com',
accounts: [
{ provider: google,
idGoogle: myid,
},
{ provider: simple,
email: my#email.com,
password: myp4ssw0rd
}
]
}
or:
{
firstname: myname,
lastname: mylastname',
email: 'email#example.com',
accounts: [
{ id: q1w2e3,provider:google},
{ id: r4t5y5, provider:simple},
]
}
and a reference to another collection
{
_id:q1w2e3,
provider:google
idGoogle:wqwqe24},
{
id: r4t5y5,
provider:simple,
email:my#email.com
password: myp4ssw0rd
}
My main goal is optimal performance with many users

I would not use a separate collection and lookup. MongoDB will manage the embedded document without much overhead. And if it starts degrading, just add an index.
The simplicity of queries with the embedded document outweighs any overhead.

Related

How to query an attribute from an object inside of an array with Mongoose

I am trying to filter a list of 'professionals' using model.find() from Mongoose. The query I have works normally in MongoDB Compass but with Mongoose it does nothing.
The model goes like this:
{
name: string,
email: string,
password: string,
phoneNumber: number,
city: string,
myDescription: string,
specialty: [
{ name: string, certificate: string, isCertified: boolean }
],
image: { profile: string, jobs: [strings] },
availability: Boolean
}
The query in MongoDB Compass is { specialties: { $elemMatch: { name: 'Soldador General', isCertified: true } } } and it returns the list of 'professionals' as expected. When I use it in Mongoose it returns the entire list, so no filter.
Going through the documentation of Mongoose there is a method Query.elemMatch() but the problem is that the filter is dynamic, I want the users to filter by city, specialty or both, and also I might add some filters in the future. For now the queries look something like:
{ specialties: { $elemMatch: { name: 'Soldador General', isCertified: true } } }
{ city: 'Barranquilla' }
{ city: 'Barranquilla', 'specialties': { $elemMatch: { name: 'Soldador General', isCertified: true } } }
And so I don't see how to do this dynamically with Query.elemMatch(). BTW I retrieve the object using React useSearchParams and send the request via NodeJS.
Any help or guidance is highly appreciated!

Require a mongodb db model deign. Whether to choose Refs or Embeded doc

I'm designing a backend for a Talent hunt application. Initially I designed the DB using refs. Like I followed the primary key forign key using refs to join my collections. But as the collection requirement increases it's being hard to join all the collections. Then I come across the one to many collections. So I'm thinking to get a suggestion from experts. Let me tell the requirements.
I have the following collections initially.
User.js
{
_id: "5ecfdc903165f709b49a4a14",
name: "Lijo",
email: "lijo#gmail.com"
}
then I have a category table for serving the categories
Category.js
{
_id: 5ecfdc903165f709b49a5a18,
title: "Acting",
code: "ACT"
}
If one user adds his talents to profile. I used one another collection for storing. Rmember the user can save multilple talents. So i created,
UserTalents.js
{
_id: "5ecfdc903165f709b49a6c87",
categoryId: "5ecfdc903165f709b49a5a18",
userId: "5ecfdc903165f709b49a4a14",
level: "beginner"
}
For each catgeory need to upload atleast one media along with description Soagain I created a new collection for that.
Media.js
{
_id: "5ecfdc903165f709b49a8a14",
talentId: "5ecfdc903165f709b49a6c87",
userId: "5ecfdc903165f709b49a4a14"
media: "5ecfdc903165f709b49a4a14_1.jpg"
}
And I need to have these users connected. For that craeted.
Friends.js
{
_id: "5ecfdc903165f709b49a8a18",
sender: "5ecfdc903165f709b49a4a14",
receiver: "5ecfdc903165f709b49a4a15"
status: "accepted"
}
Is this good to continue??? Expecting a huge amount of users. Or can I follow like:
User.js
{
_id: "5ecfdc903165f709b49a4a14",
name: "Lijo",
email: "lijo#gmail.com",
talents: [
{
_id: "5ecfdc903165f709b49a5a18", // _id from Category
title: "Acting",
code: "ACT",
level: "beginner",
media: "5ecfdc903165f709b49a4a14_1.jpg"
}
],
friends: [
{
_id: "5ecfdc903165f709b49a4a15",
name: "Test",
status: "approved"
}
]
}
I I follow this, then how do I update the name fileds in talents and friends array either one of its original name is changed?
Which is better approach?

MongoDB, How to get ObjectId that just created in Embedded document?

I'm creating a Post & Comments, and I designed to post contains comments. "Comments" is embedded document(Object Array) field that contains comment information, and uses "_id" as unique identifier. This is the code(Note that I'm using Node.js with extra mongoDB library) :
db.update('posts', {
_id: new ObjectID(postId)
}, {
$push: {
comments: {
_id: new ObjectID(),
author: comment.author,
email: comment.email,
text: comment.text
}
}
}) ...
Look at the $push, you can see that I created new ObjectId. It's working well, but I want to send back the _id that just created comment to the client, so make client can erase or edit without page refresh. How do I get the _id that just created embedded document?
How about setting them to variables when you create the ids:
const id1=new ObjectID(postId);
const id2=new ObjectID();
db.update('posts', { _id: id1 },
{ $push:
{ comments: { _id: id2,
author: comment.author,
email: comment.email,
text: comment.text } } }) ...

How to include documents as subdocuments in MongoDB?

I have a basic user collection that consists of document like so:
{
user: 3949fj9fn9rjhfne93,
name: "Jerry",
country: 'au',
friends: ['20fn39r4hf93', 'g9en3irhr934', '4i5henifuw92']
}
Each of those friends also has a document the same, along with there being a large collection of countries that can be queried via the country code.
{
code: 'AU',
name: 'Australia'
}, {
code: 'NZ',
name: 'New Zealand'
}
My question is, how would I include the full document for each of those array items within the result, like so:
{
user: 3949fj9fn9rjhfne93,
name: "Jerry",
country: {
code: 'AU',
name: 'Australia'
},
friends: [{
user: 20fn39r4hf93,
name: "Bob",
friends: ['2049429fr', 'djwij393i4']
}, {
user: g9en3irhr934,
name: "Foo",
friends: []
}, {
user: 4i5henifuw92,
name: "Bar",
friends: ['2049429fr']
}]
}
I am using Mongoose in my application, and I understand that this could be done by using a simple for loop and pushing the results to the user object and then returning it in node with res.json(user), although what if the user had hundreds (or even thousands) of friends? The request would be huge. I also need to do this in multiple places within my API.
Is there a more efficient way to achieve this?

Build query to get chat conversation messages in sails js

Lets say i have the following model schema described as below to add some chat functionality between 2 users in my sails app. For instance if i have user A sending a message to user B, then user B will reply back to user A which will always create 2 conversations between both users. So my question is how can i query both conversations to get messages from A and B. I tried something like this but maybe theres a simple logic.
// User Model
attributes: {
username: {
type: 'string',
required: true,
unique: true,
},
conversations_sender: {
collection: conversation,
via: 'sender'
},
conversations_recipient: {
collection: conversation,
via: 'recipient'
}
}
// Conversation model
attributes: {
sender: {
model: user
},
recipient: {
model: user
},
messages: {
collection: 'message',
via: 'conversation'
}
}
// Message model
attributes: {
text: {
type: 'string'
},
conversation: {
model: 'conversation'
},
}
// Conversation Controller
get: function(req, res) {
var params = {
or : [
{
sender: req.param('sender'),
recipient: req.param('recipient')
},
{
sender: req.param('recipient'),
recipient: req.param('sender')
}
]
}
Conversation.find(params) ...
}
You should rethink your schema a bit, see this link that has a good database design for your needs:
http://www.9lessons.info/2013/05/message-conversation-database-design.html
You should be able then to fetch all the messages with the 2 user ids like this:
Conversation.findAll({sender: ..., receiver: ...})
Also you will need a timestamp for the messages, in the future you'll want to sort them somehow and also make the nice 'Read yesterday' feature

Resources