Storing messages in new conversation collections; MongoDB - database

I'm a student working on a chat application for my internship, where I use socket.io.
Right now I am busy thinking of a good way to store the messages send in conversations.
As of now I do the following:
For each conversation between one user and another user, a new collection is made.
On every message sent, the message is stored in the according conversation collection in a single document.
The collections:
Where the document looks as follows:
Now I wonder if there is a good argument to be made to have just one collection "conversations", and store all the messages in multiple documents, where each conversation is a new document.

Creating a new collection for every message is very bad idea instead of that you use a simple schema as given below to store your messages
const conversation_schema = new Schema({
from: {
type: ObjectID,
ref: 'User'
},
to: {
type: ObjectID,
ref: 'User'
},
messageBody: { // body of the message(text body/ image blob/ video blob)
type: String,
},
messageType: { // type of the message(text, mp3, mp4, etc...)
type: String,
},
read: { // to boolean flag to mark whether the to user has read the message
type: Boolean,
default: false,
},
createdAt: { // when was this message goit created
type: Date,
default: new Date(),
},
});
you can fetch the conversation between the two users using the following query
conversations.find({
$or: [
{from: 'user1', TO: 'user2},
{from: 'user2', TO: 'user1},
],
}).populate({ path: 'to', model: User })
.populate({ path: 'from', model: User })
.sort({ createdAt: -1 })

Related

Updating model with GraphQL Mutation

I have been having trouble figuring out how to update a User with graphQL. The functionality I'm currently aiming for is for the user to be able to update their account/profile information. I have some things set up for the user like a bio field for their profile, and a profile picture field that's set up to take a URL and display that as their profile picture.
I have no problems when it comes to creating using graphQL. A user can sign up, log in, make posts, etc without issue. I can also update the User in regards to other models, for example, a new post pushes to the users Post data just fine.
I have not been able to figure out how to update a user directly though. Essentially I can get around this by creating a new model for "profile pic" and pushing that to the User, but that seems like it's just extra steps that might slow things down, as well as shortchanging myself being able to learn something new.
This is the User model. I have omitted a few fields due to the exact block of code being large, but this includes the "image" and "bio" fields (the fields I would like to update) as well as the reference to the Post model which I mentioned above that functions appropriately.
User.js
const userSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
match: [/.+#.+\..+/, 'Must match an email address!']
},
password: {
type: String,
required: true,
minlength: 8
},
image: {
type: String
},
bio: {
type: String,
maxLength: 500
},
posts: [
{
type: Schema.Types.ObjectId,
ref: 'Post'
}
],
},
Below is the mutation in Explorer, including the variables and the result.
Profile Pic Resolver
addProfilePic: async (parent, { image }, context) => {
if (context.user) {
const updatedUser = await User.findOneAndUpdate(
{ _id: context.user._id },
{ image: image },
{ new: true, runValidators: true }
);
return updatedUser;
}
throw new AuthenticationError('You need to be logged in!');
},
typeDefs.js (relevant only)
type Mutation {
addProfilePic(_id: ID!, image: String!): Auth
}
I notice that in the Explorer page it returns "null" for user with a 200 status. I am led to believe that means that it's not able to even access the "image" field on the user to be able to update it. When compared to my other mutations in regards to users, this is set up very similarly and I'm not sure what the difference is.
I feel like I am missing something very basic here in regards to being able to update. I haven't been able to find an update mutation example that works. Could anyone assist? My main questions would be:
Why does the mutation return "null" for user?
How can I set up my resolver to appropriately update information on an already-created object?
Thank you to anyone who is able to take a look and assist, I will be closely watching this post for replies and will update any other code someone may need to be able to assist. I've been stuck in regards to updating information for a long time, but my site is getting to the point where it's nearly ready and I need to tackle this updating issue in order to progress. Thank you!
Quick Edit: I want to add that "Auth" is referenced. The appropriate authorization headers are in place to retrieve the data. Just wanted to add that in as I highly doubt authorization has anything to do with this!
I have solved this issue and would like to leave the answer here for anyone who may find it useful.
In the mutation typeDefs, I changed the "Auth" to "User",
type Mutation {
addProfilePic(_id: ID!, image: String!): User
}
and then in the mutation itself, took away the user field like such:
mutation addProfilePic($_id: ID!, $image: String!) {
addProfilePic(_id: $_id, image: $image) {
_id
username
image
}
}
This has allowed the user to update their profile photo information. Hope this helps!

Use an array as response model in AWS Gateway cdk

I'm trying to create a typescript aws cdk to build up an API Gateway with this own swagger documentation.
There is one simple endpoint returning a list of "Supplier", but we don't know how to specify this in the cdk.
Here the code:
export function CreateSupplierMethods(apigw: apigateway.Resource,restApiId: string, scope: cdk.Construct, api: apigateway.RestApi) {
let suppliers = apigw.addResource('suppliers')
let supplierModel = new apigateway.Model(scope, "supplier-model", {
modelName: "supplier",
restApi: api,
contentType: 'application/json',
schema: {
description: "Supplier data",
title: "Supplier",
properties: {
code: { type: apigateway.JsonSchemaType.STRING, minLength: 4, maxLength: 6},
name: { type: apigateway.JsonSchemaType.STRING, maxLength: 81},
}
},
})
let getSuppliers = suppliers.addMethod('GET', new apigateway.MockIntegration(), {
methodResponses: [{
statusCode: "200",
responseModels: {
"application/json": supplierModel,
}
},
{
statusCode: "401",
}]
})
}
As you can see, the GET has the supplierModel as output.
How can I say "returns a list of supplierModel"? I wish I can use this model for both list of supplier and single instances of supplier (like a GET method with id as input).
Is this possible? If yes, how?
Looking the generated json, I'm trying to have something like this:
But what I'm getting now is quite different:
How can I get a result like the first image?
You are creating a model and assigning it to the method.
Create an array of those models and then assign that array to the method.
let supplierModelArray = new apigateway.Model(scope, "supplier-model-array", {
modelName: "supplier-array",
restApi: api,
contentType: 'application/json',
schema: {
description: "Supplier data",
title: "Supplier",
type: apigateway.JsonSchemaType.ARRAY
items: {type: supplierModel}
},
})
And change the "application/json": supplierModel in api to "application/json": supplierModelArray

Posting to mongoDb with ObjectId Many to one relationship

Mongoose/MongoDB Question
I have an Owners model containing basic profile data.
I have a secondary model: OwnersImages
e.g
{
owner: {
type: Schema.Types.ObjectId,
ref: 'Owners'
},
name: String,
imageUrl: String,
},
);
From the client I want to post the imageUrl and the name to the OwnersImages table.
e.g
let values = {
owner: this.state.user._id,
name: this.state.field,
imageUrl: this.state.url
}
axios.post(`${serverPath}/api/addFieldImage`, values)
However Im unsure how best to go about this, link it etc.
I can do a GET request on the Owners table to get the Owner data, but then posting this as part of the values to OwnerImages doesn't successfully link the two tables.
Do i need to just store a string reference to the Owner id in OwnerImages or is there a smarter way of doing this?
Or should I just post the string of the user Id to mongoose and then do a map to the Owner table from within there?
Tried to explain this best way I could but the eyes are tired so please ask if any confusion!
Many thanks
Without seeing your exact setup, I think you could modify this to fit your needs:
// In the Schema/Model files
const ownersSchema = Schema({
// other fields above...
images: [{ type: Schema.Types.ObjectId, ref: 'OwnersImages' }]
});
const ownersImagesSchema = Schema({
// other fields above...
owner: { type: Schema.Types.ObjectId, ref: 'Owners' },
});
// in the route-handler
Owners.findById(req.body.owner, async (err, owner) => {
const ownersImage = new OwnersImages(req.body);
owner.images.push(ownersImage._id);
await ownersImage.save();
await owner.save();
});
As a side-note, I think the Models generally have singular names, so Owner and OwnerImage. The collection will then automatically take on the plural form. Just food for thought.
When you want to load these, you can link them with populate(). Consider loading all of the OwnersImages associated with an Owners in some route-handler where the /:id param is the Owners id:
Owners
.findOne({ _id: req.params.id })
.populate('images')
.exec(function (err, images) {
if (err) return handleError(err);
// do something with the images...
});

Discord.Js options object

I'm actually doing a command to start a "conversation" with a player and take responses he give me. For doing that, I've the plan to use a temporary channel. I don't find a complet way to create a channel. I saw, that we have to create the channel, and after modifie it to adjust as we want. So I have this code :
m.guild.createChannel(`Candidature-${m.author.username}`, 'text', [{
type: 'role',
id: '605021521467146279',
permission: 0x400
}])
with this error :
(node:1904) DeprecationWarning: Guild#createChannel: Create channels with an options object instead of separate parameters
and I don't find real documentation about options object. Can I have some information about how it's work, and some link to learn more ?
Thanks for your help.
I can see the confusion here as the way channels are now created have been altered and here is how to create them: (var name = "blah" isn't needed but cleans it up a bit)
var name = `ticket-${numbers}`;
message.guild.createChannel(name, { type: "text" })
And to do the channel permissions you want to use .then like this:
message.guild.createChannel(name, { type: "text" }).then(
(chan) => {
chan.overwritePermissions(message.guild.roles.find('name', '#everyone'), {
'VIEW_CHANNEL': false
})
You can change the role or change it to other things such as message.author.id or mentioned users etc.
Hope this helps!
Thanks for your answers. I have do this :
m.guild.createChannel(
`Candidature-${m.author.username}`, {
type: 'text',
topic: `Salon de candidature créé par ${m.author.username} | Id du joueur : ${m.author.id}`,
parent: idCategorie,
permissionOverwrites: [{
id: m.guild.id,
deny: ['VIEW_CHANNEL'],
},
{
id: m.author.id,
allow: ['VIEW_CHANNEL'],
}
]
})
.then((chan) => {
console.log("Channel create");
});
With those links :
https://discord.js.org/#/docs/main/stable/typedef/ChannelData
https://discordjs.guide/popular-topics/permissions.html#roles-as-bot-permissions
It's creating a channel with a name, a topic, and a categorie as parent. Only the plyaer itself and administrator can see the channel.

Dynamic end-points

I have a UI component that generates a mongo schema like this
{
content: String,
date: { type: Date, default: Date.now },
author: {
type: Schema.Types.ObjectId,
ref: 'User'
}
}
the idea is take this schema and generate the end-point to get the info, the question is where do you recomend storage the schema in mongoDB or in the files somehow run programmatically
yo angular-fullstack:endpoint mySchema
Thank You

Resources