I am using graphql with mongoose and I am trying to access a nested object array in a json of this form:
"Plans": [
{
"id": ...
"name": ...
"frequency": ...
"lastExecuted": ...
"Steps": {
"Step": [
{
"id": ...
"shortDescription": ...
"description": ...
...
},
{...],
}
I created a mongoose model:
const PlanModel = Mongoose.model("Plan", {
name: String,
frequency: GraphQLString,
lastExecuted: String,
Steps: []
})
Intuitively I would insert my Stepmodel in the array, but this is giving me an error.
So I tried populating the array with the resolver:
Plans: {
type: GraphQLList(PlanType),
args: getGraphQLQueryArgs(PlanType),
resolve: (root, args, context, info) => {
return PlanModel
.find()
.populate("Steps")
.populate("Steps.Step")
.exec();
}
},
This is my PlanType:
const PlanType = new GraphQLObjectType({
name: 'Plan',
fields: () => ({
id: {
type: GraphQLID
},
name: {
type: GraphQLString
},
frequency: {
type: GraphQLString
},
lastExecuted: {
type: GraphQLString
},
maintenanceSteps: {
type: GraphQLList(StepType)
},
})
})
My GraphQL query returns an empty array in this case. I know this is a common problem, but I couldn't find any solution for my problem
The solution to my problem was adding another type:
const StepsType = new GraphQLObjectType({
name: 'Steps',
fields: () => ({
Step: {
type: GraphQLList(StepType)
}
})
})
const PlanType = new GraphQLObjectType({
name: 'Plan',
fields: () => ({
_id: {
type: GraphQLID
},
id: {
type: GraphQLString
},
name: {
type: GraphQLString
},
frequency: {
type: GraphQLString
},
lastExecuted: {
type: GraphQLString
},
status: {
type: GraphQLString
},
Steps: {
type: StepsType
},
})
})
Related
We are creating a new version our API (v2) adopting the JSON:API specification (https://jsonapi.org/). I'm not being able to port the ExtJS model associations (belongs_to) to the new pattern.
The ExtJS documentation only shows how to use a nested relation in the same root node (https://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.association.Association).
v1 data (sample):
{
"data": [
{
"id": 1,
"description": "Software Development",
"area_id": 1,
"area": {
"id": 1,
"code": "01",
"description": "Headquarters"
}
},
],
"meta": {
"success": true,
"count": 1
}
}
v2 data (sample):
{
"data": [
{
"id": "1",
"type": "maint_service_nature",
"attributes": {
"id": 1,
"description": "Software Development",
"area_id": 1
},
"relationships": {
"area": {
"data": {
"id": "1",
"type": "area"
}
}
}
}
],
"included": [
{
"id": "1",
"type": "area",
"attributes": {
"id": 1,
"code": "01",
"description": "Headquarters"
}
}
],
"meta": {
"success": true,
"count": 1
}
}
My model:
Ext.define('Suite.model.MaintServiceNature', {
extend: 'Ext.data.Model',
fields: [
{ desc: "Id", name: 'id', type: 'int', useNull: true },
{ desc: "Area", name: 'area_id', type: 'int', useNull: true },
{ desc: "Description", name: 'description', type: 'string', useNull: true, tableIdentification: true }
],
associations: [
{
type: 'belongsTo',
model: 'Suite.model.Area',
foreignKey: 'area_id',
associationKey: 'area',
instanceName: 'Area',
getterName: 'getArea',
setterName: 'setArea',
reader: {
type: 'json',
root: false
}
}
],
proxy: {
type: 'rest',
url: App.getConf('restBaseUrlV2') + '/maint_service_natures',
reader: {
type: 'json',
root: 'data',
record: 'attributes',
totalProperty: 'meta.count',
successProperty: 'meta.success',
messageProperty: 'meta.errors'
}
}
});
Any ideias on how to setup the association to work with the v2 data?
I'm honestly taking a stab at this one... I haven't used Ext JS 4 in years, and I wouldn't structure my JSON like JSON:API does, but I think the only way you can accomplish this is by rolling your own reader class. Given that you have generic properties for your data structure, this reader should work for all scenarios... although, I'm not too familiar with JSON:API, so I could be totally wrong. Either way, this is what I've come up with.
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('MyReader', {
extend: 'Ext.data.reader.Json',
alias: 'reader.myReader',
root: 'data',
totalProperty: 'meta.count',
successProperty: 'meta.success',
messageProperty: 'meta.errors',
/**
* #override
*/
extractData: function (root) {
var me = this,
ModelClass = me.model,
length = root.length,
records = new Array(length),
dataConverter,
convertedValues, node, record, i;
for (i = 0; i < length; i++) {
node = root[i];
var attrs = node.attributes;
if (node.isModel) {
// If we're given a model instance in the data, just push it on
// without doing any conversion
records[i] = node;
} else {
// Create a record with an empty data object.
// Populate that data object by extracting and converting field values from raw data.
// Must pass the ID to use because we pass no data for the constructor to pluck an ID from
records[i] = record = new ModelClass(undefined, me.getId(attrs), attrs, convertedValues = {});
// If the server did not include an id in the response data, the Model constructor will mark the record as phantom.
// We need to set phantom to false here because records created from a server response using a reader by definition are not phantom records.
record.phantom = false;
// Use generated function to extract all fields at once
me.convertRecordData(convertedValues, attrs, record, me.applyDefaults);
if (me.implicitIncludes && record.associations.length) {
me.readAssociated(record, node);
}
}
}
return records;
}
});
Ext.define('Suite.model.Area', {
extend: 'Ext.data.Model',
fields: [{
name: 'type',
type: 'string'
}]
});
Ext.define('Suite.model.MaintServiceNature', {
extend: 'Ext.data.Model',
fields: [{
desc: "Id",
name: 'id',
type: 'int',
useNull: true
}, {
desc: "Area",
name: 'area_id',
type: 'int',
useNull: true
}, {
desc: "Description",
name: 'description',
type: 'string',
useNull: true,
tableIdentification: true
}],
associations: [{
type: 'belongsTo',
model: 'Suite.model.Area',
associatedName: 'Area',
foreignKey: 'area_id',
associationKey: 'relationships.area.data',
instanceName: 'Area',
getterName: 'getArea',
setterName: 'setArea'
}],
proxy: {
type: 'rest',
url: 'data1.json',
reader: {
type: 'myReader'
}
}
});
Suite.model.MaintServiceNature.load(null, {
callback: function (record) {
console.log(record.getData(true));
}
});
}
});
I am using sequelize for my backend and I want to add a where condition with YYYY-mm-dd
In mysql we use date_format(dateCreated, "%d-%m-%Y").
But how to achieve it in Sequelize. I searched all over the google but nothing helped me out
My present Sequelize query. I want to get data of dateCreated = '2020-05-31'.
const apartmentOrdersData = await apartments_order.findAll(
{
where: { apid: req.body.apid }, group: ['apcid'],
attributes: ['apcid', [sequelize.fn('sum', sequelize.col('totalCost')), 'total_amount'],],
include: [apartments_child]
});
My model:
const { DataTypes, Model } = require('sequelize');
const sequelize = require('../../../mysql_connection/sequilize');
const admins = require('./admins');
const apartments_child = require('./apartments_child');
class apartments_order extends Model { }
apartments_order.init({
// Model attributes are defined here
apoid: {
type: DataTypes.INTEGER,
primaryKey: true
},
invoiceNo: {
type: DataTypes.STRING
},
apid: {
type: DataTypes.INTEGER
},
apcid: {
type: DataTypes.INTEGER
},
apcbid: {
type: DataTypes.INTEGER
},
totalCost: {
type: DataTypes.DECIMAL
},
dateCreated: {
type: DataTypes.DATE
},
dateUpdated: {
type: DataTypes.DATE
},
createdBy: {
type: DataTypes.STRING
},
updatedBy: {
type: DataTypes.STRING
},
status: {
type: DataTypes.STRING
}
}, {
sequelize,
timestamps: false,
logging: false,
tableName: 'apartments_order'
});
apartments_order.hasOne(admins, { foreignKey: 'aid', sourceKey: 'createdBy' });
apartments_order.hasOne(apartments_child, { foreignKey: 'apcid', sourceKey: 'apcid' });
module.exports = apartments_order;
One thing that you can do is use a setter and getter for the columns.
Follow an example (on your field declaration, you can manipulate the data inside getter() and setter():
dateUpdated: {
type: Sequelize.STRING,
defaultValue: '[]',
get() {
const d = this.getDataValue('dateUpdated');
return format(d, 'Y-m-d');
},
set(value) {
return this.setDataValue('dateUpdated', format(value, <your-format-here>)
},
type: DataTypes.DATE,
},
I would like to display some information about members, but I don't know how to resolve array of field 'time'. This is array, because it shows their login time. What should I do?
I used GraphQLString, but I am aware of this bad solution.
So I'm getting an error:
"message": "String cannot represent value: [\"12:08\"]",
Here is schema.js
const axios = require("axios");
const {
GraphQLObjectType,
GraphQLString,
GraphQLList,
GraphQLSchema
} = require("graphql");
const memberType = new GraphQLObjectType({
name: "Member",
fields: () => ({
nick: {
type: GraphQLString
},
name_and_surname: {
type: GraphQLString
},
time: {
type: GraphQLString
}
})
});
//Root Query
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
users: {
type: new GraphQLList(memberType),
description: "List of members",
resolve(parent, args) {
return axios
.get("http://25.98.140.121:5000/data")
.then(res => res.data);
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
});
And here is JSON
[
{
"time": [
"12:08"
],
"nick": "Cogi12",
"name_and_surname: "John Steps"
},
{
"time": [
"12:16"
],
"nick": "haris22",
"name_and_surname": "Kenny Jobs"
},
{
"time": [
"12:07",
"12:08",
"12:17",
"12:19",
"12:45",
"13:25"
],
"nick": "Wonski",
"name_and_surname": "Mathew Oxford"
}
]
you can use GraphQLList along with GraphQLString for time type like this,
const memberType = new GraphQLObjectType({
name: "Member",
fields: () => ({
nick: {
type: GraphQLString
},
name_and_surname: {
type: GraphQLString
},
time: {
type: new GraphQLList(GraphQLString)
}
})
});
I am using GraphQL, Sequelize, and MySql to add data to Clients Table. In the GraphQl Mutation, I do the following:
const db = require("./models");
const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
addClient: {
type: ClientType,
args: {
lastName: { type: new GraphQLNonNull(GraphQLString) },
firstName: { type: new GraphQLNonNull(GraphQLString) },
primaryPhoneNumber: { type: new GraphQLNonNull(GraphQLString) },
cellphone: { type: GraphQLString },
workPhone: { type: GraphQLString },
email: { type: GraphQLString },
UserId: { type: new GraphQLNonNull(GraphQLString) }
},
resolve(parentValue, args) {
let newClient = new db.Client({
lastName: args.lastName,
firstName: args.firstName,
primaryPhoneNumber: args.primaryPhoneNumber,
cellphone: args.cellphone,
workPhone: args.workPhone,
email: args.email,
UserId: args.UserId
});
console.log(newClient);
return db.Client.create(newClient);
}
}
}
});
But I receive this error back when testing it on GraphiQL:
{
"errors": [
{
"message": "notNull Violation: Client.lastName cannot be null,\nnotNull Violation:
Client.firstName cannot be null",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"addClient"
]
}
],
"data": {
"addClient": null
}
}
I believe this error comes from sequelize as in my Model I define some Non-Null fields:
module.exports = function(sequelize, DataTypes) {
var Client = sequelize.define(
"Client",
{
lastName: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
firstName: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
primaryPhoneNumber: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
cellphone: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
workPhone: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
email: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
}
},
{
timestamps: false
}
);
Client.associate = function(models) {
// Associating Clients with Pets
// When a Client is deleted, also delete any associated Pets
Client.belongsTo(models.User);
Client.hasMany(models.Pet, {
onDelete: "cascade"
});
};
return Client;
};
This is my query from the front end:
mutation {
addClient(lastName: "ali", firstName: "muhamed", primaryPhoneNumber:
"00990099009", email: "jalimaƱa#email.com", UserId: "14fb9610-4766-11ea-9a4e-
e130bc08c2aa") {
lastName,
firstName
}
}
Does anybody know why is this happening? Any help will be highly appreciated.
Model.create takes a plain object with the values the Model instance should be initialized with. You shouldn't pass an existing instance of Model to it. Instead, just call the save method on the instance.
const instance = new SomeModel({ firstName: 'Bob' })
await instance.save()
This is equivalent to
const instance = SomeModel.build({ firstName: 'Bob' })
await instance.save()
and
await SomeModel.create({ firstName: 'Bob' })
I am learning GraphQL and trying to get data from MySql tables via sequelize in the resolve function on GraphQL. I have a Clients table associated with a Pets Table, where Pets belong to Client.
Here is my code:
const PetsType = new GraphQLObjectType({
name: "Pet",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
breed: { type: GraphQLString },
type: { type: GraphQLString },
ClientId: { type: GraphQLString },
Comments: {
type: CommentsType,
resolve(parentValue, args) {
return db.Comments;
}
}
})
});
const ClientType = new GraphQLObjectType({
name: "Client",
fields: () => ({
id: { type: GraphQLString },
lastName: { type: GraphQLString },
firstName: { type: GraphQLString },
primaryPhoneNumber: { type: GraphQLString },
cellphone: { type: GraphQLString },
workPhone: { type: GraphQLString },
email: { type: GraphQLString },
Pets: {
type: PetsType,
resolve(parentValue, args) {
return db.Pet.findOne({
where: { ClientId: parentValue.id }
});
}
}
})
});
Using findOne works for clients with only one pet or only returns the first pet of a client who owns more than one. However, some clients have more than one pet, so findOne() doesn't really solve my problem.
I've tried:
return db.Pet.findAll({
where: { ClientId: parentValue.id }
});
But it returns the client with the fields on Pets null.
Here are my Sequelize models for both, Clients and Pets:
Clients:
module.exports = function(sequelize, DataTypes) {
var Client = sequelize.define(
"Client",
{
lastName: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
firstName: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
primaryPhoneNumber: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
cellphone: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
workPhone: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
},
email: {
type: DataTypes.TEXT,
allowNull: true,
len: [1]
}
},
{
timestamps: false
}
);
Client.associate = function(models) {
// Associating Clients with Pets
// When a Client is deleted, also delete any associated Pets
Client.belongsTo(models.User);
Client.hasMany(models.Pet, {
onDelete: "cascade"
});
};
return Client;
};
Pets:
module.exports = function(sequelize, DataTypes) {
var Pet = sequelize.define(
"Pet",
{
name: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
breed: {
type: DataTypes.TEXT,
allowNull: false,
len: [1]
},
type: {
type: DataTypes.TEXT,
allowNull: true
}
},
{
timestamps: false
}
);
Pet.associate = function(models) {
Pet.belongsTo(models.Client);
Pet.hasMany(models.Comment, {
onDelete: "cascade"
});
};
return Pet;
};
How can I retreive all Pets that belong to this client?
Thanks in advance.
As Daniel Rearden suggested, I changed it to: type: new GraphQLList(PetsType) to return a list of objects