Populating the "Ref" in mongoose schema while working with Graphql - javascript

I am working with Graphql and then I come to a situation where I need to populate, but I am not getting how to excute that.
Here is my Booking schema
const mongoose=require('mongoose')
const Schema=mongoose.Schema
const bookingschema=new Schema({
event:{
type:Schema.Types.ObjectId,
ref:'Event'
},
user:{
type:Schema.Types.ObjectId,
ref:'User'
}
}
,{timestamps:true})
module.exports=mongoose.model('Booking',bookingschema)
Here is my resolver to create a booking event
bookevent: async args => {
const fetchevent = await Event.findOne({ _id: args.eventid });
const booking = new Booking({
user: "5d64354bfd7bb826a9331948",
event: fetchevent
});
const result = await booking.save();
return {
...result._doc,
_id: result._id,
createdAt: new Date(result._doc.createdAt).toISOString(),
updatedAt: new Date(result._doc.updatedAt).toISOString()
};
}
};
When i try to run the graphql query i easily get what i require
mutation{
bookevent(eventid:"5d6465b4ef2a79384654a5f9"){
_id
}
}
gives me
{
"data": {
"bookevent": {
"_id": "5d64672440b5f9387e8f7b8f"
}
}
but now how do I populate user here ???
cause at the end I want this query to be executed successfully
mutation{
bookevent(eventid:"5d6465b4ef2a79384654a5f9"){
_id
user{
email
}
}
Schema of eventtype is
type Event{
_id:ID!
title:String!
description:String!
price:Float!
date:String!
creator:User!
}
cause my user schema has email inside it and I am trying to reach that out
So where in my Booking resolver should I populate "user" ??
To resolve the user I did
const result = await booking.save();
const res=await result.populate("user");
console.log(res) //doesnt gives the populated user only gives me id
If I am not wrong for these cases populate is the way right?

I hope it may help you.
const result = await booking.save();
const res=await booking.findById(result._id).populate("user");
console.log(res)

I have never made anything like this before but after saving new Booking here:
const result = await booking.save();
You can use .populate() on result. Example:
await result.populate("user");
Or if the above not work:
await result.populate("user").execPopulate();

Related

React Native: Convert the value stored in AsyncStorage into an object

I am making a simple CRUD app using React Native with MongoDB, NodeJS and Express. When the user registers, the _id is saved inside AsyncStorage to check if the user is already authenticated or not every time he/she opens the app.
const response = await axios.post('API_LINK', {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
})
const data = await response.data
console.log(data)
await AsyncStorage.setItem('userId', data.user._id)
console.log(data) returns
Object {
"user": Object {
"__v": 0,
"_id": "62e42244b7bc9e7f9de5131b",
"email": "testing5#gmail.com",
"name": "Test 5",
"password": "$2a$10$SE7Eq46mBXGw7FYBtOtqqO49wvIMYDl0LfHknrrp.rWdrYNr6Dk8.",
"projects": Array [],
},
}
The projects [] contains all the projects created by that particular user. So, in the Project Model and Controller, the userId is also passed, so that the specific project is stored in the projects array of that specific user whose userId is passed.
ProjectModel
const projectSchema = new Schema({
title: {
~~~~~~~~~~~~~~~~~~~~~~~~~~~
},
description: {
~~~~~~~~~~~~~~~~~~~~~~~~~~~
},
user: {
type: mongoose.Types.ObjectId,
ref: 'User',
required: true
}
})
Project Controller
export const createProject = async (req, res, next) => {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let userExists
try {
userExists = await User.find(user)
} catch (err) {
return console.log(err)
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const project = new Project({
title,
description,
user
})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
CreateProject
const userId = await AsyncStorage.getItem('userId')
const response = await axios.post('http://IP_ADDRESS:8000/api/project/create', {
title: title.trim(),
description: description.trim(),
image: image.trim(),
user: userId
})
But on clicking Create button, this error is shown
ObjectParameterError: Parameter "filter" to find() must be an object, got 62e42244b7bc9e7f9de5131b, linking to the createProject inside Project Controller.
Then, I saw that _id stored as userId is string, so I tried to convert it to object using JSON.parse().
const userId = await AsyncStorage.getItem('userId')
const userId2 = JSON.parse(userId)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
user: userId2
But, now I get this error JSON Parse error: Unable to parse JSON string.
So, how to convert the userId stored in AsyncStorage into object? And, if there are any other better methods to perform this task, please suggest.

react Firestore query nested collection where field then update, or add new doc

I'm currently ripping my hair out trying to query a nested collection in my Firestore db.
my db is set up as follows:
users (collection)
- username
- displayName
- ratedItems (collection)
- itemId
- timestamp
- likedItem
I want to be able to add/update the rated item in the ratedItems collection for a specific user but I seem to be hitting 2 problems:
I assume the query is incorrect as if(querySnapshot.empty) always returns false even if there are no matching items (matching the itemId) in the ratedItems collection, so it always attempts to add a new item which results in duplicate entries in the collection.
if I force the code to bypass the conditional it throws an error when it attempts to update the existing item:
Expected type 'mc', but it was: a custom yc object
My thoughts are I am using the collectionGroup query incorrectly but I haven't found a solution for this yet. Should I even be using collectionGroup at all?? from what I've read, if I understand correctly this will query every ratedItem collection regardless of the user, which isn't what I want
const rateItem = async (itemId, liked) => {
try {
const itemRef = collection(db, 'users', currentUser.uid, 'ratedItems');
const q = query(
collectionGroup(db, 'users', currentUser.uid),
where('itemId', '==', itemId)
);
const querySnapshot = await getDocs(q);
if (querySnapshot.empty) {
await addDoc(itemRef, {
itemId: itemId,
timestamp: serverTimestamp(),
likedItem: liked,
});
} else {
await updateDoc(itemRef, {
timestamp: serverTimestamp(),
likedItem: liked,
});
}
} catch (err) {
console.log(err.message);
}
};
I assume the query is incorrect as if(querySnapshot.empty) always returns false even if there are no matching items (matching the itemId) in the ratedItems collection, so it always attempts to add a new item which results in duplicate entries in the collection.
You used the itemRef for both of addDoc and updateDoc which is not the proper way to do it. You need a correct query syntax in order to update your Firestore document.
if I force the code to bypass the conditional it throws an error when it attempts to update the existing item
You can try the code below to update your nested document:
const updateitemRef = query(
collection(db, 'users', 'user_item', 'ratedItems'),
where('itemId', '==', itemId)
);
const itemSnapshot = await getDocs(updateitemRef);
itemSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
updateDoc(doc.ref, {
likedItem: liked,
timestamp: serverTimestamp()
});
});
For the complete code, you can try the code below:
const rateItem = async (itemId, liked) => {
try {
const q = query(
collectionGroup(db, 'users', currentUser.uid),
where('itemId', '==', itemId)
);
const querySnapshot = await getDocs(q);
const additemRef = collection(db, 'users', currentUser.uid, 'ratedItems');
const updateitemRef = query(
collection(db, 'users', currentUser.uid, 'ratedItems'),
where('itemId', '==', itemId)
);
const itemSnapshot = await getDocs(updateitemRef);
if (querySnapshot.empty) {
await addDoc(additemRef, {
itemId: itemId,
likedItem: liked,
timestamp: serverTimestamp()
});
} else {
itemSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
updateDoc(doc.ref, {
likedItem: liked,
timestamp: serverTimestamp()
});
});
}
} catch (err) {
console.log(err.message);
}
};
For more references in creating a query, you can refer to the guides below:
Add a document
Perform simple and compound queries in Cloud Firestore

Mongoose keep duplicate elements

I have a function that create guild entry for DiscordJS, but when the script start and also if the function is called multiple times, it create around 400 duplicate documents, it create by ID and the ID is unique, so it's not normal
My schema structure only have a ID type String and unique is true
client.createGuild = async guild => {
const exist = await Guild.findOne({ id: guild.id });
if(!exist) {
await Guild.create({ id: guild.id }); // new Guild().save() keep duplicate too
}
}
It look like the if statement doesn't exist
const Schema = mongoose.Schema;
const FooSchema = new Schema({
id: { type: String, index: true, unique: true }
});
const Foo = mongoose.model('Foo', FooSchema);
Foo.createIndexes();
If collection already exists. Create index manually to the collection via atlas or cmd.
You can combine getData and createData functions to one. Here is the example:
const mongoose = require('mongoose');
async function getData(Guild, guild) {
if (!mongoose.connection.readyState) await mongoose.connect('MONGO_URL'); // In case you haven't connect to database
const data = await Guild.findOne({ id: guild.id }); // get data from database
if (!data) {
return new Guild({
id: guild.id,
}); // If no data exists for the guild, return new model
}
return data; // If the data already exists, return that
}
Now if you want to get data from mongodb you just call the function. It automatically create and save a new one if there is not.
Comment if you still have any problem or you have got what you need.
Make sure to call the function with await or it won't return the data.

Update array inside of Mongo document doesn't work

I have a user's collection, each user has a subscription array of objects. I want to add another subscription to that array. I'm getting the new subscription, updating it with findByIdAndUpdate, but it doesn't add the new subscription, however it shows that the document was updated. I tried several approaches but nothing worked well.
Here is the last approach:
...
const { user_id } = req.params;
const subscription = req.body; // Getting subscription
const user = await UserModel.findById(user_id).lean().exec(); // Getting user by id
const { push_subscriptions } = user; // Getting subscribtions with destructuring
const updated_subs = [...push_subscriptions, subscription];
// Getting user another time and updating the push_subscriptions array
const updated_user = await UserModel.findByIdAndUpdate(user_id,
{push_subscriptions: updated_subs},
{ new: true }
).exec();
...
Here are the logs of request body and params
// body
{
endpoint: 'https://fcm.googleapis.com/fcm/send/cQ6wlRJ8t-s:APA91bEjqdLMzQLsroJ7zHzdjrzoshdPD8IJy_iIeRa8qV_Yjt6N1jeMUtyMq73wSn9JJT-4WXr_8uwHXttj-XFxHPCPAOqgN7zALsmf_BeIRZowRBTRHf9YH8v3AlcaZXWAIQ0qJNdn',
expirationTime: null,
keys: {
p256dh: 'BBPC5h1QnBMPKMfPacgJu_2RFT7LAejyINh3CvP4pamkrlERr06YpRlSb7RbTUOn6MYW4adG93KfdEWXz68F9iQ',
auth: 'Zl3iaOdBvihXG2QVOb26IQ'
}
}
//params
{ user_id: '5fedc679f414663c693cf549' }
User schema, push_subscriptions part:
push_subscriptions: {
type: Array,
},
Your query looks good, you can do single query using $push instead of doing manual process,
const { user_id } = req.params;
const subscription = req.body;
const updated_user = await UserModel.findByIdAndUpdate(user_id,
{
$push: {
push_subscriptions: subscription
},
{ new: true }
).exec();

Mongoose: TypeError: Cannot read property 'findOne' of undefined

I am working on billing in node.js and I created a new Model Stripecustomer where I save the stripe customer id and this customer's email. I kinda copied the main code form my other mongoose models and changed it. I had hoped to instantly start using it but when I tried to find a document in this model I got the following error:
⛔️ Error:
TypeError: Cannot read property 'findOne' of undefined
I have looked at it for half an hour and I can't see what I did wrong. Can anyone tell me where I did something wrong?
workspace.controller.js: here is where I try to create a subscription. Stripecustomer is undefined, but I don't get why since I imported it on top
const stripe = require("stripe")("sk_test_dvebbZQPA4Vk8kKZaEuN32sD");
const {
Group, User, Workspace, Stripecustomer
} = require('../models');
const { sendErr } = require('../../utils');
const billing = async (req, res) => {
try {
const email = 'tijl.declerck#outlook.com';
// get the payment plan
const plan = await stripe.plans.retrieve('plan_EK1uRUJLJcDS6e');
// get the stripe customer or create a new one
let customer;
const existingCustomerDoc = await Stripecustomer.findOne({ email: email });
// if we couldn't find an existing customer in our database...
if (!existingCustomerDoc[0]) {
// then we create a new customer
customer = await stripe.customers.create({
email,
source: 'src_18eYalAHEMiOZZp1l9ZTjSU0'
});
} else {
// we retrieve this customer in stripe
customer = await stripe.customers.retrieve(existingCustomerDoc.customer_id);
}
// subscribe the customer to the plan
// You now have a customer subscribed to a plan.
// Behind the scenes, Stripe creates an invoice for every billing cycle.
// The invoice outlines what the customer owes, reflects when they will be or were charged, and tracks the payment status.
// You can even add additional items to an invoice to factor in one-off charges like setup fees.
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{ plan: plan.id }]
});
res.status(200).json({
message: 'payment complete',
obj: subscription
});
} catch (err) {
return sendErr(res, err);
}
};
stripecustomer.model.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const stripeCustomerSchema = new Schema({
email: {
type: String,
required: true
},
customer_id: {
type: String,
required: true
}
});
const Stripecustomer = mongoose.model('Stripecustomer', stripeCustomerSchema);
module.exports = Stripecustomer;
The error is probably coming from ur models index.js file, can u share ur models/index.js file to make this more clear, because findOne is a mongoose function, if u get undefined it means Stripecustome is not an instance of a mongoose model

Categories