Unable to insert data into db where a collection has a relationship - javascript

This is in a Node project where I am trying to write a graphql api for a simple blog.
I am using apollo and behind the scenes attempting to save data to a mongo db via mongoose.
I am currently getting the following error when I try to save a Post data.
"GraphQLError: ID cannot represent value: { type: "Buffer", data:
[Array] }", "at GraphQLScalarType.serialize
(/Users/name/projects/graphtime/node_modules/graphql/type/scalars.js:301:11)",
It is complaining about the Author insertion as part of the Post I believe.
Is there something wrong with my schema or how I am performing the query on the Apollo GraphiEditor?
The is the DB Schema
import mongoose from "mongoose";
const authorSchema = new mongoose.Schema({
name: { type: String, required: true },
avatar: { type: String },
});
export const Author = mongoose.model('Author', authorSchema);
const postSchema = new mongoose.Schema({
title: { type: String, required: true },
authors: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Author'
}
]
});
export const Post = mongoose.model('Post', postSchema);
This is the graphql Schema
type Post {
id: ID!
title: String
authors: [Author]
}
type Author {
id: ID!
name: String
avatar: String
}
type Mutation {
addPost(
title: String!,
authors: [ID!],
): Post
}
This is the grapql resolver.
const resolvers = {
Mutation: {
addPost: (_, args, context) => {
const newPost = new Post({
title: args.title,
authors: args.authors,
});
return newPost.save();
},
},
};
This is how I am querying in the editor which throws the error.
P.S: The DB already has an existing author in there and lets say the id for that row is: 63babc44e18d174016b03433
mutation {
addPost(
title: "New Post",
authors: ["63babc44e18d174016b03433"],
) {
title
authors {
id
name
}
}
}

You have defined the mutation in this way:
type Mutation {
addPost(
title: String!,
authors: [ID!],
): Post
}
That's mean addPost return a Post object, which is:
type Post {
id: ID!
title: String
authors: [Author]
}
So authors is an array of Authors objects, not the _ids.
You are getting the ID and saving into DB but the returned object does not match [Author]. Also note how the postSchema is mongoose.Schema.Types.ObjectId. Referenced to Authors, yes, but is an array of IDs.
So you can return an array of IDs instead the Author object or populate the query in mongoose because you have the reference.

Related

Cast to ObjectId failed for value \"\" (type string) at path \"category\" because of \"BSONTypeError\

I have the Cast to error in JSON response when Adding the Product Details in the & when adding category showing Error.
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
{
category: {
type: ObjectId,
ref: "Category",
},
};
Except category Every detail is adding in the mongodb table
You should try mongoose.SchemaTypes.ObjectId
#Prop({ type: mongoose.SchemaTypes.ObjectId, ref: 'ExercisePlan' })
category: string;
And if you are trying to aggregate with _id so you should try
$match: {
category: new Types.ObjectId(inputId),
},

how to return a Mongoose nested array of objects

I am trying to return a nested Object that I declared in my mongoose model as follows:
const MessageSchema = new Schema({
messageLog: [
{
transcript: {
type: String
},
recipient: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
sender: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
}
}]
});
however I am not able to get the value for the inner object back when I try to query for it via a graphql resolver (transcript, sender, recipient are null on gql playground, but updated in db) I have set it up as follows:
query = args.messageId ? { _id: args.messageId } : { _id: new ObjectId() };
const message = await Message.findOneAndUpdate(query, {$addToSet: {messageLog: {transcript: args.messageBody, sender: args.senderId, recipient: args.recipientId}}}, {$setOnInsert: args, upsert: true, new: true, runValidators: true})
return message.messageLog;
I am able to create the new object and the nested messageLog in the db but I can only return the id for some reason as opposed to the the messageLog array of objects. Usually the issue lies in how I am resolving (resolvers) but I am going to put my typeDef here as well in case the issue lies there.
type Message {
_id: ID
transcript: [String]
recipient: [User]
sender: [User]
}
So the solution in case anyone has a similar schema setup and issue is to reference the the typeDefs with the nested levels as well. So since transcript, recipient and sender were nested a level down, the typeDef would have to be defined for the nested object and then referenced on the message type as follows:
type messageLog {
_id: ID
transcript: String
recipient: User
sender: User
}
type Message {
_id: ID
messageLog: [messageLog]
}
and to use populate for the User since it was a schema referenced by the objectId

GraphQL: TypeError: Cannot read property of undefined

I have an Apollo GraphQL projects where I have created my own Query and Mutations. I have done using mock data and Query and Mutation works fine. But when I am trying to do with Sequelize ORM, I am getting the error
"TypeError: Cannot read property 'getListings' of undefined",
" at listings (/home/ayman/Desktop/apollo-graphql/graphql-app/functions/graphql.js:50:19)",
" at field.resolve (/home/ayman/Desktop/apollo-graphql/graphql-app/node_modules/graphql-extensions/dist/index.js:134:26)"
Query and Mutations in graphql.js:
const { ApolloServer, gql} = require("apollo-server-lambda");
const { Listing, User } = require("../db");
const jwt = require("jsonwebtoken");
const typeDefs = gql`
type Query {
listings: [Listing!]!
}
type Mutation {
createListing(input: CreateListingInput!): Listing!
}
input CreateListingInput {
title: String!
description: String
url: String!
notes: String
}
type Contact {
id: ID!
name: String!
company: Company
email: String
notes: String
}
type Company {
id: ID!
name: String!
logo: String
listings: [Listing!]!
url: String
}
type Listing {
id: ID!
title: String!
description: String
url: String!
notes: String
company: Company
contacts: [Contact!]!
}
`;
const resolvers = {
Query: {
listings(_, __, { user }) {
return user.getListings();
},
},
Mutation: {
createListing(_, { input }, { user }) {
return Listing.create({ ...input, userId: user.id });
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
exports.handler = server.createHandler();
I have Sequilize along with Postgres database:
db.js
const Sequelize = require("sequelize");
const sequelize = new Sequelize(process.env.DB_CONNECTION_STRING, {
dialect: "pg",
dialectModule: require('pg'),
dialectOptions: {
ssl: true,
},
});
class User extends Sequelize.Model {}
User.init(
{
email: Sequelize.STRING,
password: Sequelize.STRING,
},
{
sequelize,
modelName: "user",
}
);
class Listing extends Sequelize.Model {}
Listing.init(
{
title: Sequelize.STRING,
description: Sequelize.TEXT,
url: Sequelize.STRING,
notes: Sequelize.TEXT,
},
{
sequelize,
modelName: "listing",
}
);
Listing.belongsTo(User);
User.hasMany(Listing);
exports.sequelize = sequelize;
exports.User = User;
exports.Listing = Listing;
Github Link
Run using netlify dev
Go to URL: http://localhost:8888/.netlify/functions/graphql
Sample GraphQL query
{
listings {
id
title
description
url
company {
name
url
}
}
}
return user.getListings();
you probably mean User, because user is undefined
I see, you are trying to access user object from context. Please check the context definition. It should return an object containing user object explicitly.

How to reach information already saved in other related models... MongoDB, NodeJS

I'm really new at this and I want to practice queries and tried to make a very different exercise but it didn't went as I expected.
I got three models:
const userSchema = new Schema({
info1: String,
info2: String,
},
const serviceSchema = new Schema(
{
name: String,
legalOwner: {
type: Schema.Types.ObjectId,
ref: 'User',
},
},
const orderSchema = new Schema(
{
client: { type: Schema.Types.ObjectId, ref: 'User' },
service: { type: Schema.Types.ObjectId, ref: 'Service' },
description: String
},
My users can behave like a legal owner or a client. I want to show the info that a user set as a LegalOwner, previously. And that is already saved in Mongo, How can I have access that data, is there a query for that? Do I need to set it in my model Order?
const orderSchema = new Schema(
{
client: { type: Schema.Types.ObjectId, ref: 'User' },
service: { type: Schema.Types.ObjectId, ref: 'Service' },
description: String,
legalOwner: { type: Schema.Types.ObjectId, ref: 'Service' },
},
I tried a lot of things on this query. But nothing works ...
await Order.findById(id).populate('service')
ObjectId are stored as _id within mongoDb as far as I am aware of.
Try this
const query = { _id: new ObjectID(id)};
await Order.findOne(query).populate('service')
Also import ObjectID from mongodb node_module as
import { ObjectID } from 'mongodb';

Mongoose populate and search by populated field

I am trying to do a simple search on a field that is a ref of another collection. Say I have the example collection of Invoices with a reference to a collection named client. So the example schema would look like so:
const invoiceSchema = new Schema({
name: {
type: String,
required: true
},
amount: {
type: Number,
required: true
},
client: {
type: Schema.Types.ObjectId,
ref: 'Client'
},
}
Then I have the client schema like so:
const clientSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
}
}
What I want to do is query the invoice schema and search for the name field in the client.
I have tried to use find and match with populate but that just returns the entire invoices collection and the client field is null on all of them:
const q = new RegExp(req.body.q, 'i');
invoices = await Invoice.find().populate({
path: 'client',
match: {
name: q
}
});
So how should I go about searching for a populated field with mongoose?

Categories