GraphQL relational data vs MongoDB document references - javascript

I'm new to GraphQL and am trying to learn the best way to use it with MongoDB. GraphQL has a way to define the relationship between types as following:
type Booking {
id: ID!
date: String!
author: [User!]!
event: [Event!]!
}
But, MongoDB also has a way to define the references between documents as following:
event: {
type: Schema.Types.ObjectId,
ref: 'Event'
},
author: {
type: Schema.Types.ObjectId,
ref: 'User'
}
If I wanted to retrieve the authors of the Booking, I can either perform the search on the GraphQL's end in the resolver as following:
Booking: {
author(parent, args, ctx, info) {
return users.filter(user => {
return user.id === parent.author;
})
}
},
or I can use a MongoDB find() method on the result to find the authors from the Booking.find() in the resolver as following:
bookings: async () => {
try {
const bookings = await Booking.find();
return bookings.map(booking => {
return //perform MongoDB find() here to get the authors using the references
});
} catch (err) {
throw err;
}
My question is, is it necessary to define the relationship between data on the GraphQL's side as well as on the MongoDB side? Which way of the two mentioned above is a better way to retrieve relational data?

Related

How can i display newest user post in my app?

How can i display newest user post in my app? i have a backend route which display user post but i want that route display latest post of user So how can i do that in my code?
My code:
router.get('/postdata', async (req, res) => {
try {
// Find all users in the database
const users = await User.find();
// Map over the users array and return an array of objects
// with the same username, profile_image, and postImage
const userData = users.flatMap(user => {
return user.posts.map(post => ({
username: user.username,
profile_image: user.profilepic,
postImage: post.post,
}));
});
return res.json(userData);
} catch (err) {
return res.status(500).json({ error: err.message });
}
});
If your posts model has created_at or updated_at properties that keep track of when an image was uploaded, you could use that to sort the array in your map.
Let's say your userData array has similar output to this.
[
{
username: 'user1',
profile_image: 'https://your_domain.com/user1-profile.jpg',
postImage: 'https://your_domain.com/user1-post1.jpg',
created_at: '2023-01-01T11:00:00.000
},
{
username: 'user2',
profile_image: 'https://your_domain.com/user2-profile.jpg',
postImage: 'https://your_domain.com/user2-post1.jpg',
created_at: '2023-01-01T12:00:00.000
}
]
Then you can sort the array before rendering it.
const sorteduserData = userData.sort((a, b) => {
return new Date(b.created_at) - new Date(a.created_at);
});
It's a good practice to have your backend do the sort to reduce overhead on the front-end and to have your application load faster.
Many of headless CMSs have these features built in.

How does GraphQL Mutation associate itself with Type

When I set up my schema as following:
type Mutation {
createUser(data: CreateUserInput!): User!
}
type User {
id: ID!
name: String!
password: String!
email: String!
posts: [Post!]!
comments: [Comment!]!
}
and my resolver:
const Mutation = {
async createUser(parent, args, { prisma }, info) {
if(args.data.password.length < 8) {
throw new Error("Pasword must be 8 characters or longer")
}
return prisma.mutation.createUser({
data: {
...args.data,
password
}
})
}
}
how does GraphQL know that createUser is associated with my User model? I could set it up so that createUser returns token instead of User (after generating a token) or I could rename createUser to createPerson. I have never defined the association between createUser and User. I'm unsure how my data input through createUser gets directed to be saved in the user table, instead of another table.
There is no association between the two.
Your resolver could just as easily return a plain object with some dummy data:
async createUser(parent, args, { prisma }, info) {
...
return {
id: 1,
name: 'Kevvv',
password: 'password',
email: 'kevvv#stackoverflow.com',
}
}
or use some other means of fetching the user:
async createUser(parent, args, { prisma }, info) {
...
return fetchUserFromAPI()
// or some other data source like a DB
}
prisma.mutation.createUser returns a Promise that resolves to an object which represents the created user. This object happens to have properties that match the User type you specified in your schema, but otherwise there's nothing "special" about it.

NodeJS MongoDB processing and storing huge amount of text

I have a NodeJS Express APP and I am building an endpoint to update Terms&Conditions
http://127.0.0.1:3000/api/admin/info/terms/de?version=2
However the text I'm trying to store is way too heavy (text has tabs, single and double quotes and so on), and requires a ton of editing in order to be placed in a json body {"terms":"easy text"}. {"terms": "heavy "text//"" that . "I dont" wish to""" editööäääÄÄ""}
What's the best way of handling this kind of text? Convert it to binary and then send it?
My endpoint
router.post('/terms/:language', async (req, res) => {
try {
const { language } = req.params;
const { version } = req.query;
const { terms } = req.body;
if (!version) return res.status(400).json({ message: 'Field "version" is empty' });
let info = await PageInfo.findOne({ $and: [{ version }, { language }] });
if (info) {
const update = await PageInfo.findOneAndUpdate({ version: { $eq: version } }, {
$set: {
version,
terms,
language
}
}, { new: true });
return res.status(200).json({ type: 'update', data: update });
}
info = await PageInfo.create({
version,
terms,
language,
});
return res.status(200).json({ type: 'new', data: info });
} catch (e) {
return res.sendStatus(500);
}
});
It looks like GridFS is what you will want to use.
You can read more about it here: GridFS
If this doesn't solve your issue, based on my experience, these kinds of issues arise when your schema is poorly modeled so you may want to reconsider how you model it.

return response result of following mongoose's schema

I've been using node (express) with mongoose for a while but I have little clue about mongoose's schema. What I know is it throw you an error and prevent you to do any db operation if the request object (like req.body.firstName) you pass is not exist in the schema.
How can I return my api result according the schema? for example I have a schema like this
const UserSchema = mongoose.Schema({
first: {
type: String
},
last: {
type: String
}
}
module.exports.getAllUsers = (callback) => {
User.find({}, (err,result => {
console.log(result)
})
}
I might not get first and last property in my array, I get whatever data that store in the users collection.
Does it means every response I have to manually do
res.json({
first,
last
})
I'm looking an option to return response that will follow mongoose's schema.

Find one element, use data, then delete it

In my node.js application I'm currently implementing a "Remember Me" functionality. Everything works quite well so far, but I have a problem with mongoose. What I want to do: I have a model named Token with this schema:
var TokenSchema = mongoose.Schema({
token: { type: String },
uid: { type: Schema.Types.ObjectId, ref: 'User' }
});
This is simply a little collection that maps cookie tokens to a UserId. Then I have this function here:
function consumeRememberMeToken(token, fn) {
Token
.findOne({ 'token': token }, (err, result) => {
return (result===null)?fn(null, null):fn(null, result.uid);
})
.remove();
}
What it should do, is this: find the uid for a given token string and return it (if there is a result). But this function should also delete the entry right after returning the uid.
At the moment, the uid from the found token result gets returned properly, but it (the result Token) does not get deleted from the collection with the above code. I don't understand how to remove it right after getting it and using the retrieved uid. I'm completely new to functional programming and I don't understand how and where to delete the token.
You can try db.collection.findOneAndDelete It deletes the document and returns the deleted data, quite the reverse of what you are saying but basically serves your purpose. here are the details.
Also here is the mongoose representation of the same.
Token.findOne({ 'token': token }, (err, result) => {
if(err || !result) return fn(err || "error", null);
else{
var uid = result.uid;
result.remove(function(){
return fn(null, uid);
});
}
})

Categories

Resources