Having error fetching nested object data using graphql - node.js

I am trying to fetch the below response using graphql
....................................................................................................................................................................................................
{
"monthly": {
"starter": {
"type": "Starter",
"price": "200",
},
"scale": {
"type": "Scale",
"price": "540",
},
"organization": {
"type": "Organization",
"price": "1600",
},
"custom": {
"type": "Custom",
}
},
"_id": "62b3afea60638efd887210b5",
}
Normally with express I fetch the response with the code below
exports.getPricing = async (req, res) => {
try {
const pricing = await Pricing.find({});
return res.status(200).json(_.head(pricing));
} catch (error) {
return res.status(500).json(error.message);
}
};
But I tried using graphql to fetch same response using the code below
const { GraphQLObjectType, GraphQLString, GraphQLList, GraphQLSchema } = graphql;
const PrcingType = new GraphQLObjectType({
name:'Pricing',
fields: () => ({
monthly:{
starter: {
type: {type: GraphQLString},
price: {type: GraphQLString},
description: {type: GraphQLString},
chargeAmount: {type: GraphQLString},
interviewTemplate: {type: GraphQLString},
customQuestions: {type: GraphQLString},
yearlyPrice: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
description: {type: GraphQLString},
included: {type: GraphQLString},
chargeAmount: {type: GraphQLString},
interviewTemplate: {type: GraphQLString},
customQuestions: {type: GraphQLString},
yearlyPrice: {type: GraphQLString},
},
organization: {
type: {type: GraphQLString},
price: {type: GraphQLString},
description: {type: GraphQLString},
included: {type: GraphQLString},
chargeAmount: {type: GraphQLString},
interviewTemplate: {type: GraphQLString},
customQuestions: {type: GraphQLString},
yearlyPrice: {type: GraphQLString},
},
custom: {
type: {type: GraphQLString},
price: {type: GraphQLString},
description: {type: GraphQLString},
included: {type: GraphQLString},
chargeAmount: {type: GraphQLString},
interviewTemplate: {type: GraphQLString},
customQuestions: {type: GraphQLString},
yearlyPrice: {type: GraphQLString},
}
},
})
});
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
books: {
type: new GraphQLList(PrcingType),
resolve(parent, args){
return Pricing.find({});
},
},
}
});
module.exports = new GraphQLSchema({
query: RootQuery
});
But am getting error showing
{
"errors": [
{
"message": "The type of Pricing.monthly must be Output Type but got: undefined."
}
]
}

Related

Having error querying and using mutation in graphql

I am trying to add nested object data to mongodb database using graphql and also fetch the data using the code below
........................................................................................................................................................................................................
const graphql = require('graphql');
const Pricing = require('../models/pricing');
const { GraphQLObjectType, GraphQLString, GraphQLID,
GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLSchema } = graphql;
const PrcingType = new GraphQLObjectType({
name:'Pricing',
fields: () => ({
monthly:{
starter: {
type: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
},
},
quarterly: {
starter: {
type: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
},
},
})
});
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
pricings: {
type: new GraphQLList(PrcingType),
resolve(parent, args){
return Pricing.find({});
},
},
}
});
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addPricing: {
type: PrcingType,
args: {
monthly:{
starter: {
type: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
},
},
quarterly: {
starter: {
type: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
},
},
},
resolve(parent, args){
let pricing = new Pricing({
monthly:{
starter: {
type: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
},
},
quarterly: {
starter: {
type: {type: GraphQLString},
},
scale: {
type: {type: GraphQLString},
price: {type: GraphQLString},
},
},
});
return pricing.save();
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery,
mutation: Mutation
});
But when I run the grapghql server I get this error
{
"errors": [
{
"message": "The type of Pricing.monthly must be Output Type but got: undefined."
},
{
"message": "The type of Pricing.quarterly must be Output Type but got: undefined."
},
{
"message": "The type of Mutation.addPricing(monthly:) must be Input Type but got: undefined."
},
{
"message": "The type of Mutation.addPricing(quarterly:) must be Input Type but got: undefined."
}
]
}
What am I doing wrong?

Node.js Mongodb GraphQL - mutations and query

I have problem with some parts of my code:
const BookType = new GraphQLObjectType({
name: "Book",
fields: () => ({
id: {type: GraphQLID},
title: {type: GraphQLString},
author: {type: GraphQLString},
})
})
const fQuery = new GraphQLObjectType({
name: "firstQuery",
fields: {
books: {
type: new GraphQLList(BookType),
resolve(parent, args){
return Book.find({});
}
},
book: {
type: BookType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
return Book.findById(args.id);
}
},
author: {
type: BookType,
args: {author: {type: GraphQLString}},
resolve(parent, args){
return ??????????
}
},
}
})
I don't know how to find book by author.
Next thing - mutations:
const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
add: {
type: BookType,
args: {
title: {type: GraphQLString},
author: {type: GraphQLString},
},
resolve(parent,args){
let book = new Book({
title:args.title,
author:args.author,
})
return book.save()
}
},
update: {
type: BookType,
args: {
title: {type: GraphQLString},
author: {type: GraphQLString},
},
resolve(parent, args){
return Book.findByIdAndUpdate(args.id, {
title: args.title,
author: args.author
})
}
},
del: {
type: BookType,
args: {
id: {type: GraphQLID},
},
resolve(parent,args){
return Book.findByIdAndDelete(args.id)
}
}
}
});
Update does not work. Delete removes the first item, not the selected one by ID. This is my homework assignment. I've been sitting on this for a few hours now and can't seem to get it right.
Do anyone of you know how to fix this?
thanks in advance!
UPDATE: Searching by author does not work. I was able to fix the rest.
You also need an author GraphQLObjectType and if you store the id of the author in your books you can add a new field in author
EDIT: Also you can try find by name (but it must be unique or you will have conflicted results)
booksByAuthor: {
type: GraphQLList(BookType),
async resolve(parent, args) {
return Books.find( { id:parent.id } )
},
}
So will be something like
const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
booksByAuthor: {
type: GraphQLList(BookType),
async resolve(parent, args) {
return Books.find({ id: parent.id });
},
},
}),
});
I don't see the id as argument in your mutation. You need to pass the id.
update: {
type: BookType,
args: {
id:{type: GraphQLID}
title: {type: GraphQLString},
author: {type: GraphQLString},
},
resolve(parent, args){
return Book.findByIdAndUpdate(args.id, {
title: args.title,
author: args.author
})
}
},
I'm new to this as well but I hope it helps

How can I use Mongoose.populate - it doesn't work

Can anybody help me please?
I have two schemas and models (I add full version of code to be clearly):
const HouseSchema: Schema = new Schema(
{
name: {type: Schema.Types.String, required: true},
class: {type: KeyDisplayNameSchema},
levels: {type: Schema.Types.Number},
price: {type: Schema.Types.Number, required: true},
beginDate: {type: Schema.Types.String},
squarePrice: {type: Schema.Types.Number},
order: {type: Schema.Types.Number, default: 0},
parking: {type: Schema.Types.Boolean},
endDate: {type: Schema.Types.String},
visibleInCarousel: {type: Schema.Types.Boolean, default: true},
isDeleted: {type: Schema.Types.Boolean, default: false},
apartmentComplex: {
type: Schema.Types.ObjectId,
ref: 'ApartmentComplex'
},
images: {
type: imagesSchema,
default: () => {
return {};
}
},
publishedDate: {type: Schema.Types.String}
},
{
toJSON: {virtuals: true},
toObject: {virtuals: true}
}
);
HouseSchema.virtual('sections', {
ref: 'Section',
localField: '_id',
foreignField: 'house'
});
HouseSchema.virtual('flats', {
ref: 'Flat',
localField: '_id',
foreignField: 'house'
});
HouseSchema.virtual('layouts', {
ref: 'HouseLayout',
localField: '_id',
foreignField: 'house'
});
HouseSchema.virtual('levelLayouts', {
ref: 'LevelLayout',
localField: '_id',
foreignField: 'house'
});
HouseSchema.virtual('parkingComplex', {
ref: 'ParkingComplex',
localField: '_id',
foreignField: 'houses'
});
const HouseModel = mongoose.model<House>('House', HouseSchema);
export default HouseModel;
const ParkingComplexSchema: Schema = new Schema(
{
name: {type: Schema.Types.String, required: true},
address: {type: Schema.Types.String},
city: {type: KeyDisplayNameSchema, required: true},
district: {type: KeyDisplayNameSchema, required: true},
undergroundStation: {type: KeyDisplayNameSchema},
levels: {type: Schema.Types.Number, required: true},
beginDate: {type: Schema.Types.String, required: true},
endDate: {type: Schema.Types.String},
isDeleted: {type: Schema.Types.Boolean, default: false},
houses: [
{
type: Schema.Types.ObjectId,
ref: 'House',
default: () => {
return [];
}
}
],
developer: {
type: Schema.Types.ObjectId,
ref: 'Developer'
},
apartmentComplex: {
type: Schema.Types.ObjectId,
ref: 'ApartmentComplex'
}
},
{
toJSON: {virtuals: true},
toObject: {virtuals: true}
}
);
ParkingComplexSchema.virtual('parkingPlaces', {
ref: 'ParkingPlace',
localField: '_id',
foreignField: 'parkingComplexId'
});
const ParkingComplexModel = mongoose.model<ParkingComplex>('ParkingComplex', ParkingComplexSchema);
export default ParkingComplexModel;
These models have ref's to each other.
Then I want to get Parking Complex and populate field 'houses'
If I do this:
getParkingComplex: async (parent, {uuid}) => {
const data = await ParkingComplexModel.findById(uuid).exec()
console.log(data)
return data;
}
I get Parking Complex and field 'houses' has two objectId of House:
{
isDeleted: false,
houses: [ 60aaa827ec89de07e0fb8db1, 60aaa827ec89de07e0fb8db2 ],
_id: 60aaa827ec89de07e0fb8db3,
levels: 2,
beginDate: '2021-09-23T19:07:45.190Z',
endDate: '2023-05-23T19:07:45.194Z',
developer: 5ecd1c2590de761738c029a3,
apartmentComplex: 5ecd20b290de761738c029ad,
__v: 0,
id: '60aaa827ec89de07e0fb8db3'
}
But if I do this:
getParkingComplex: async (parent, {uuid}) => {
const data = await ParkingComplexModel.findById(uuid)
.populate('houses')
.exec()
console.log(data)
return data;
}
I get empty array of 'houses':
{
isDeleted: false,
houses: [],
_id: 60aaa827ec89de07e0fb8db3,
levels: 2,
beginDate: '2021-09-23T19:07:45.190Z',
endDate: '2023-05-23T19:07:45.194Z',
developer: 5ecd1c2590de761738c029a3,
apartmentComplex: 5ecd20b290de761738c029ad,
__v: 0,
id: '60aaa827ec89de07e0fb8db3'
}
What I do wrong? Thank for help!
Could you be...because you set the default return value for houses as an empty array?
...
houses: [
{
type: Schema.Types.ObjectId,
ref: 'House',
default: () => {
return [];
}
}
],
....

Populate nested array with Mongoose

I have a user schema as shown below and I'm trying to populate the live projects array but I can't figure out how to access it.
const userSchema = new Schema({
local: {
email: String,
username: String,
password: String,
liveProjects: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'liveProject'
}]
},
google: {
googleId: String,
email: String,
username: String,
liveProjects: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'liveProject'
}]
}
});
const User = mongoose.model('user', userSchema);
module.exports = User;
If it wasn't embedded I could just use
User.findById(id).populate('liveProjects').exec((err,projects)=>{});
But how do I get access to 'local.liveProjects' or 'google.liveProjects' so that I can populate them?
Turns out it is just as simple as
User.findById(id).populate('local.liveProjects').exec((err,projects)=>{});
User Schema Here
`let UserSchema = new Schema({
email: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
profile: {
firstName: {type: String,required: true},
lastName: {type: String,required: true},
address1: {type: String},
address2: {type: String},
city: {type: String},
state: {type: String},
zip: {type: String},
phone: {type: String,required: true},
avatar:{ type: Schema.Types.ObjectId, ref: 'Avatar'},
shippingAddress:{
address1: {type: String},
address2: {type: String},
city: {type: String},
state: {type: String},
zip: {type: String}
},
},
redemptionCards : [{ type: Schema.Types.ObjectId, ref: 'CardCodes' }]
});`
Logic to get RedemptionCards:-
User.findOne({ email }).populate("redemptionCards")
.exec(function (err, user) {
CardData.populate(user.redemptionCards, {path: 'redemptionCards',match: { _id: { $ne: null }}}, function (err, cards) {
console.log(cards);
});
FYI - CardData is the Hardcoded JSON file. Hope this helps.

Mongoose returns null array when populate

I'm trying to create a webapp with mongoose and nodejs. This is the first time i'm using mongoose and nodejs so i'm not quit good at it.
I have a person model:
var PERSON = new mongoose.Schema({
name: {type: String, required: true},
zipcode: {type: String, required: true},
city: {type: String, required: true},
street: {type: String, required: true},
address: {type: Number, required: true},
email: {type: String, required: true},
type: {type: String, enum: ['lid', 'passant'], required: true},
ships: {
type: [{
name: {type: String, required: true},
length: {type: Number, required: true},
type: {type: String, required: true},
picture: {type: Buffer, required: false}
}],
required: false
},
user: {
type: {
userName: {type: String, required: true},
password: {type: String, required: true},
passwordKey: {type: String, required: true},
roles: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'role'}], required: true}
},
required: false
}
},
{
collection: 'PERSON'
});
And the rol model:
var ROLE = new mongoose.Schema({
name: {type: String, required: true}
},
{
collection: 'ROLE'
});
When i'm trying to run a find query on the person model, I want to populate the user.roles array. But as a result it remains empty.
/ GET a specific person by id or type/
server.get('/api/person/:id', function (req, res, next) {
if (helper.isValidObjectID(req.params.id)) {
person.findById(req.params.id).populate("user.roles").exec(function (err, result) {
if (err) {
res.status(404).json(err);
} else {
res.status(200).json(result);
}
}
);
} else {
next();
}
}, function (req, res, next) {
person.find({type: req.params.id}).populate('user.roles').exec(function (err, result) {
if (err) {
res.status(404).json(err);
} else {
res.status(200).json(result);
}
});
});
and as a result i get:
{
"_id":"553f79d4f1481c0c14b42d59",
"name":"Wilco Boogert",
"zipcode":"4305RH",
"city":"Ouwerkerk",
"street":"baalpapenweg",
"address":2,
"email":"wilcoboogert17#gmail.com",
"type":"lid",
"user":{
"userName":"wboogert",
"password":"sha1$168fd599$1$502b965cb083ebdfcafb17e655455ef63779e1a1",
"passwordkey":"kfjvlksdfm",
"roles":[
]
},
"__v":0,
"ships":[
{
"name":"titanic",
"length":269,
"type":"Olympic-klasse",
"_id":"553f79d4f1481c0c14b42d5a"
}
]
}
The orginal object in the database is:
{
"_id": {
"$oid": "553f79d4f1481c0c14b42d59"
},
"name": "Wilco Boogert",
"zipcode": "4305RH",
"city": "Ouwerkerk",
"street": "baalpapenweg",
"address": 2,
"email": "wilcoboogert17#gmail.com",
"type": "lid",
"user": {
"roles": [
{
"$oid": "5522996f0fff331ed03cae6c"
}
],
"passwordkey": "kfjvlksdfm",
"password": "sha1$168fd599$1$502b965cb083ebdfcafb17e655455ef63779e1a1",
"userName": "wboogert"
},
"ships": [
{
"name": "titanic",
"length": 269,
"type": "Olympic-klasse",
"picture": "<Binary Data>",
"_id": {
"$oid": "553f79d4f1481c0c14b42d5a"
}
}
],
"__v": 0
}
so as you an see the roles is empty. And I search the web but i cannot find what the problem is. Can annyone help me?
You should replace this line :
roles: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'role'}], required: true}
with this one :
roles: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'ROLE'}], required: true}
In fact, the reference must be the exact same name as it's defined :
collection: 'ROLE'
It's case sensitive.

Resources