Cannot read properties of undefined (reading `fieldname`) GraphQL - node.js

i am working on a project based on GraphQL API with nodejs And mongoose
so i have this Model Below :
const mongoose = require('mongoose')
const BreakingNewsSchema = new mongoose.Schema({
MainInfo:{
content:{type:String,required:true},
ParentCategory:{
type: mongoose.Schema.Types.ObjectId,
ref: 'ArticleCategory',
required: true
},
category:{
type: mongoose.Schema.Types.ObjectId,
ref: 'ArticleCategory',
required: true
},
},
options:{
clickable:{type:Boolean,required:true},
link:{type:String,required:false},
isActive:{type:Boolean,required:true,default:true}
},
infos:{
createdAt: { type: String, required: true},
updateDate: {type: String, required: false},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
updatedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: false,
}}} ,{
timestamps: true})
module.exports = mongoose.model("BreakingNews", BreakingNewsSchema)
and i have this GraphQL Schema here :
const BreakingType = new GraphQLObjectType({
name: "BreakingNews",
fields: () => ({
id: {
type: GraphQLID
},
MainInfo: {
type: new GraphQLObjectType({
name: "BreakingMainInfo",
fields: () => ({
content: {
type: GraphQLString
},
ParentCategory: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.MainInfo.parentCategory)
}
},
category: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.MainInfo.category)
}
}
})
})
},
options: {
type: new GraphQLObjectType({
name: "BreakingOptions",
fields: () => ({
clickable: {
type: GraphQLBoolean
},
link: {
type: GraphQLString
},
isActive: {
type: GraphQLBoolean
}
})
})
},
})})
For the breakingNews Collection in Mongodb
and below i have the Category Collection ... so here is the Category Model :
const CategorySchema = new mongoose.Schema({
MainInfo:{
title: {
type: String,
required: true,
unique: true
},
slug: {
type: String,
required: false,
unique: true
},
},
seo:{
metaDescription: { type: String, required: false },
metaKeywords: [{
type: String,
required: false
}]
},
options:{
isParent:{type:Boolean,required:true},
isEnded:{type:Boolean,required:true},
parentCategory: {
type: mongoose.Schema.Types.ObjectId,
ref: "ArticleCategory",
required: false,
set: v => v === '' ? null : v
}
},
info:{
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
updatedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: false
},
articleCount:{type:Number,required:false},
oldId: { type: String, required: false }
}}, {
timestamps: true})
module.exports = mongoose.model("ArticleCategory", CategorySchema)
And finally i have the ArticleCategory Schema for GraphQL :
const CategoryType = new GraphQLObjectType({
name: "ArticleCategory",
fields: () => ({
id: {
type: GraphQLID
},
MainInfo: {
type: new GraphQLObjectType({
name: "ArticleCategoryMainInfo",
fields: () => ({
title: {
type: GraphQLString
},
slug: {
type: GraphQLString
}
})
})
},
seo: {
type: new GraphQLObjectType({
name: "ArticleCategorySeo",
fields: () => ({
metaDescription: {
type: GraphQLString
},
metaKeywords: {
type: new GraphQLList(GraphQLString)
}
})
})
},
options: {
type: new GraphQLObjectType({
name: "ArticleCategoryOptions",
fields: () => ({
isParent: {
type: GraphQLBoolean
},
isEnded: {
type: GraphQLBoolean
},
parentCategory: {
type: CategoryType,
resolve(parent, args) {
return Category.findById(parent.options.parentCategory)
}
}
})
})
}
})})
The problem is when i try to execute this query on graphQL:
query{
ActiveBreakingNews{
id
MainInfo{
content
ParentCategory {
id
}
category{
id
}
}
}
}
I get this error Cannot read properties of undefined (reading 'category') or Cannot read properties of undefined (reading 'category')
i find out its a problem find resolve function in the schema ... but i don't know what the wrong and what should i do to fix it ... please Help and thanks in advance

Related

How to return documents in mongoose and express js which are associated with only logged in user?

Here i have two mongoose models orders and users which have one to many relationship.
user.model.js
import mongoose from "mongoose";
const userSchema = mongoose.Schema(
{
firstname: {
type: String,
required: [true, "Name is required"],
},
lastname: {
type: String,
required: [true, "LastName is required"],
},
email: {
type: String,
required: [true, "Email is required"],
unique: true,
},
password: {
type: String,
required: [true, "Password is required"],
},
isAdmin: { type: Boolean, default: false },
},
{
timestamps: true,
}
);
const User = mongoose.model("User", userSchema);
export default User;
order.model.js
import mongoose from "mongoose";
const orderSchema = mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
customerId: { type: String },
paymentIntentId: { type: String },
products: [
{
id: { type: String },
name: { type: String },
category: { type: String },
price: { type: String },
size: { type: String },
color: { type: String },
thumbnail: { type: String },
qty: { type: Number },
},
],
// subTotal: { type: Number, required: true },
total: { type: Number, required: true },
shipping: { type: Object, required: true },
deliveryStatus: { type: String, default: "pending" },
paymentStatus: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
const Order = mongoose.model("Order", orderSchema);
export default Order;
I have some orders created by different users in my database. Now i am trying to get those specific orders associated with currently logged in user.
order.controller.js
export const getAllOrders = async (req, res) => {
const { _id } = req.user;
// console.log(typeof id);
try {
const orders = await Order.find({userId: _id});
console.log(orders);
res.status(200).json({ orders });
} catch (error) {
res.status(500).json({ msg: error.message });
}
};
I have tried this one but it always return an empty array.

Cannot populate when I use Foreign key in mongoose

I tried to join three documents in mongodb using mongoose in nodejs, but unfortunately this error occurs. My mongoose version is 6.2.3
Declaring Schema
const mongoose = require('mongoose')
const declaringSchema = mongoose.Schema({
cniDeclaring: { type: Number, required: true },
father: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Father',
required: true,
},
mother: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Mother',
required: true,
},
name: { type: String, required: true },
surname: { type: String, required: true },
birthDay: { type: Date, required: true },
birthPlace: { type: String, required: true },
gender: { type: String, required: true },
address: { type: String, required: true },
relationShipDeclared: { type: String, required: true },
phone: { type: Number, required: true },
request: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Request',
}],
});
module.exports = mongoose.model('Declaring', declaringSchema);
Declared Schema
const mongoose = require('mongoose')
const declaredSchema = mongoose.Schema({
name: { type: String, required: true },
surname: { type: String, required: true },
father: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Father',
},
mother: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Mother',
},
birthDay: { type: Date, required: true },
birthPlace: { type: String, required: true },
gender: { type: String, required: true },
nationality: { type: String, required: true },
request: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Request',
},
});
module.exports = mongoose.model('Declared', declaredSchema);
Father Schema
const mongoose = require('mongoose')
const fatherSchema = mongoose.Schema({
cniFather: { type: Number, required: true },
nameP: { type: String, required: true },
surname: { type: String, required: true },
birthDay: { type: Date, required: true },
birthPlace: { type: String, required: true },
address: { type: String, required: true },
phone: { type: Number, required: true },
occupation: { type: String, required: true },
declaring: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Declaring',
}],
declared: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Declared',
}],
});
module.exports = mongoose.model('Father', fatherSchema);
Now I want to get all the fathers back
const Father = require('../models/Father');
exports.createFather = (req, res, next) => {
const father = new Father({
...req.body
});
father.save()
.then(() => res.status(201).json({ message: 'Father created !'}))
.catch(error => res.status(400).json({ error })
);
}
exports.getAllFathers = (req, res, next) => {
Father.find()
.populate('declarings')
.populate('declareds')
.exec((err, res) => {
if(err){
console.log(err);
}
});
};
and I have the following error:
MongooseError: Cannot populate path declarings because it is not in your schema. Set the strictPopulate option to false to override.

How to get data from mongoDB on the basis of a value inside a nested object

Below is my API for fetching all the orders of a specific restaurant from a mongoDB database.
My search is based on the restaurant id which I am getting from params and passing it to the query object.
query1 is working but query2 does not return my data.
It is returning an empty array. If I pass a simple object in find() then I am getting a response. But when i use a nested object for getting data I get nothing.
exports.getOrders = async (req, res) => {
const restId = req.params.restId;
console.log("restaurant id", restId);
if (!restId) return res.status(404).send("No restaurant ID found in params");
const query1 = {grandTotal: 600};
const query2 = { restaurant: { restaurantId: restId } };
const response = await Orders.find(query2);
console.log("Printing response inside API function", response);
}
Below is my MongoDB Schema of Orders.
const mongoose = require("mongoose");
const orderSchema = mongoose.Schema({
customer: {
name: {
type: String,
required: true,
},
contact: {
type: String,
required: true,
},
customerId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Customer",
required: true,
},
customerAddress: {
type: String,
required: true,
},
},
restaurant: {
restaurantName: {
type: String,
required: true,
},
contact: {
type: String,
required: true,
},
restaurantId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
required: true,
},
},
/*date: {
day: {
type: Number,
required: true,
},
month: {
type: String,
required: true,
},
year: {
type: Number,
required: true,
},
},
type: {
type: String,
enum: ["delivery","takeaway"],
required: true,
},*/
items: [
{
itemId: { type: String, required: true },
itemName: { type: String, required: true },
itemDescription: { type: String, required: true },
price: {type: Number, required: true},
quantity: { type: Number, required: true },
total: {type: Number, required: true},
},
],
grandTotal: {type: Number, required: true},
status: {
type: String,
enum: ["pending", "rejected","cancelled","accepted","received"],
required: true,
},
});
orderSchema.virtual("booking", {
ref: "Booking",
localField: "_id",
foreignField: "orderId",
});
orderSchema.set("toObject", { virtual: true });
orderSchema.set("toJSON", { virtual: true });
const Orders = mongoose.model("Orders", orderSchema);
exports.Orders = Orders;
change query2 to this
const query2 = { "restaurant.restaurantId": restId } };

How to delete the referenced document in one collection and its record from the referred other collection

In my NodeJS API and MongoDB, I'm trying to delete a record which is a reference to another collection.
What I would like to do is to delete the referred objectId and the records related to the other collection which is referred.
I have 2 models Profiles and Posts and I want to delete the same one post from Profile and Post collection.
I was able to delete the reference id in Profile but I don't know how to delete also the record from Posts collection.
I tried this:
async delete(req, res) {
try {
// Match with username and pull to remove
await Profile.findOneAndUpdate(
{ _id: res.id._id },
{ $pull: { posts: req.params.postId } },
err => {
if (err) {
throw new ErrorHandlers.ErrorHandler(500, err);
}
res.json({ Message: "Deleted" });
}
);
} catch (error) {
res.status(500).send(error);
}
}
And my 2 models:
// Here defining profile model
// Embedded we have the Experience as []
const { Connect } = require("../db");
const { isEmail } = require("validator");
const postSchema = {
type: Connect.Schema.Types.ObjectId,
ref: "Post"
};
const experienceSchema = {
role: {
type: String,
required: true
},
company: {
type: String,
required: true
},
startDate: {
type: Date,
required: true
},
endDate: {
type: Date,
required: false
},
description: {
type: String,
required: false
},
area: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
username: {
type: String,
required: false
},
image: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
}
};
const profileSchema = {
firstname: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
trim: true,
lowercase: true,
unique: true,
required: [true, "Email is required"],
validate: {
validator: string => isEmail(string),
message: "Provided email is invalid"
}
},
bio: {
type: String,
required: true
},
title: {
type: String,
required: true
},
area: {
type: String,
required: true
},
imageUrl: {
type: String,
required: false,
default: "https://via.placeholder.com/150"
},
username: {
type: String,
required: true,
unique: true
},
experience: [experienceSchema],
posts: [postSchema],
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
}
};
const collectionName = "profile";
const profileSchemaModel = Connect.Schema(profileSchema);
const Profile = Connect.model(collectionName, profileSchemaModel);
module.exports = Profile;
const { Connect } = require("../db");
const reactionSchema = {
likedBy: {
type: String,
unique: true,
sparse: true
}
};
const postSchema = {
text: {
type: String,
required: true,
unique: true,
sparse: false
},
profile: {
type: Connect.Schema.Types.ObjectId,
ref: "Profile",
},
image: {
type: String,
default: "https://via.placeholder.com/150",
required: false
},
createdAt: {
type: Date,
default: Date.now,
required: false
},
updatedAt: {
type: Date,
default: Date.now,
required: false
},
reactions: [reactionSchema],
comments: {
type: Connect.Schema.Types.ObjectId,
ref: "Comment",
required: false
}
};
const collectionName = "post";
const postSchemaModel = Connect.Schema(postSchema);
const Post = Connect.model(collectionName, postSchemaModel);
module.exports = Post;
Just add a query to remove the post after pulling it's ID from the profile collection:
async delete(req, res) {
try {
// Match with username and pull to remove
await Profile.findOneAndUpdate(
{ _id: res.id._id },
{ $pull: { posts: req.params.postId } },
// You don't need an error callback here since you are
// using async/await. Handle the error in the catch block.
);
await Posts.remove({ _id: req.params.postId });
} catch (error) {
// This is where you handle the error
res.status(500).send(error);
}
}

Nested Objects in GraphQL Schema in NodeJS

I'm creating a GraphQL Server using Node JS.
I'm trying to replicate the mongo Schema which has a nested object purely for organisation. This is my mongo schema:
var plansSchema = new Schema({
planName: {
type: String,
required: [true, "Plan name is required"]
},
pricing: {
monthly: Number,
scanEnvelope: Number,
initalScan: Number,
perPage: Number,
forwardMail: Number,
forwardParcel: Number,
shred: Number,
perMonthPerGram: Number,
freeStorePerGram: Number,
setup: Number,
idFree: Number
},
expires: Number,
private: Boolean,
deleted: Boolean,
date: { type: Date, default: Date.now },
});
I'm trying to replicate this in a GraphQL schema, so far I have the following:
const PlanType = new GraphQLObjectType({
name: "Plan",
fields: () => ({
id: { type: GraphQLString },
planName: { type: GraphQLString },
pricing: new GraphQLObjectType({
name: "Pricing",
fields: () => ({
expires: { type: GraphQLInt },
private: { type: GraphQLBoolean },
monthly: { type: GraphQLInt },
scanEnvelope: { type: GraphQLInt },
initalScan: { type: GraphQLInt },
perPage: { type: GraphQLInt },
forwardMail: { type: GraphQLInt },
forwardParcel: { type: GraphQLInt },
shred: { type: GraphQLInt },
perMonthPerGram: { type: GraphQLInt },
freeStorePerGram: { type: GraphQLInt },
setup: { type: GraphQLInt },
idFree: { type: GraphQLInt }
})
})
})
});
But I'm getting the following errro in GraphiQL
{
"errors": [
{
"message": "The type of Plan.pricing must be Output Type but got: undefined."
}
]
}
Each field in the GraphQLFieldConfigMapThunk or GraphQLFieldConfigMap that you set as your fields must be a GraphQLFieldConfig object that includes properties like type, args, resolve, etc. You cannot set a field to a GraphQLObjectType like you're doing with the pricing field. In other words, your code should look more like this:
const PricingType = new GraphQLObjectType({
name: "Pricing",
fields: () => ({
expires: { type: GraphQLInt },
private: { type: GraphQLBoolean },
monthly: { type: GraphQLInt },
scanEnvelope: { type: GraphQLInt },
initalScan: { type: GraphQLInt },
perPage: { type: GraphQLInt },
forwardMail: { type: GraphQLInt },
forwardParcel: { type: GraphQLInt },
shred: { type: GraphQLInt },
perMonthPerGram: { type: GraphQLInt },
freeStorePerGram: { type: GraphQLInt },
setup: { type: GraphQLInt },
idFree: { type: GraphQLInt }
})
})
const PlanType = new GraphQLObjectType({
name: "Plan",
fields: () => ({
id: { type: GraphQLString },
planName: { type: GraphQLString },
pricing: { type: PricingType },
}),
})

Resources