Data null after saving entity with Moongose and GraphQL - node.js

When saving an entity with mongoose and graphql the following happens:
First method to save:
create(budgetProps){
const budget = new Budget(budgetProps);
return budget.save();
}
The result is as follows:
{
"data": {
"addBudget": {
"_id": "59fbdefaa7b0a81180dd2c9c",
"tiempoAproximado": 2245.5,
"User": {
"name": null,
"organization": null
},
"Vehicle": {
"name": null,
"type": null
}
}
}
}
Using this method:
create(budgetProps){
const budget = new Budget(budgetProps);
return budget.save().then((res)=>{
Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec((err, newBudget)=> {
return newBudget;
});
});
},
I get the following:
{
"data": {
"addBudget": null
}
}
This is the Schema:
const typeDefs = `
scalar Date
input UserInput {
_id: ID,
name: String,
organization: String,
phones: [String],
emails: [String],
type: String,
password: String,
percentaje: String
}
input VehicleDescriptionInput {
es: String,
en: String
}
input VehicleInput{
_id: ID,
name: String,
passengers: Int,
largeBags: Int,
smallBags: Int,
doors: Int,
type: String,
status: Boolean,
imagesUrls: [String],
description: VehicleDescriptionInput
}
input FinalTotalCostInput {
es: String,
en: String
}
input BudgetTotalCostInput {
es: String,
en: String
}
input BudgetInput {
finalTotalCost: FinalTotalCostInput,
budgetTotalCost: BudgetTotalCostInput,
destinoInicial: String,
destinoFinal: String,
tiempoAproximado: Float,
distancia: Float,
tollCost: Float,
tolls: [String],
budgetDate: Date,
aprove: Boolean,
User: UserInput,
Vehicle: VehicleInput
}
type Mutation {
addBudget(data: BudgetInput): Budget
}
`;
Here is the resolver:
Mutation: {
addBudget: (_, {data}) =>{
return BudgetController.create(data);
}
},
Finally here is the mutation with its variables:
mutation addBudget($budget: BudgetInput) {
addBudget(data: $budget) {
_id
User{
name
organization
}
Vehicle{
name
type
}
}
}
{
"budget": {
"finalTotalCost": {
"es": "100 peso",
"en": "10 dolars"
},
"budgetTotalCost": {
"es": "80 peso",
"en": "8 dolars"
},
"destinoInicial": "Queretaro",
"destinoFinal": "Sonora",
"tiempoAproximado": 2245.5,
"distancia": 100.565,
"tollCost": 20.5,
"tolls": [
"GDL",
"Marina",
"Culap",
"MalageƱa"
],
"budgetDate": "2017/07/21",
"aprove": false,
"User": {
"_id": "59fbcc42aa82460924e5fbad"
},
"Vehicle": {
"_id": "59fbcbe4aa82460924e5fbac"
}
}
}
The entity is stored properly in the database, when Console.log the result of the populated search results are correct then I do not understand what is happening.
You can find the whole app in the following link: GitHub Repo

You're mixing Promises and callbacks. exec() will return a Promise, but only if doesn't have any arguments passed to it. Additionally, you need to return the Promise that's returned by exec().
return budget.save().then((res) => {
return Budget.findById(res._id) // missing return here
.populate('User')
.populate('Vehicle')
.exec() // don't need anything else
})
You can clean this up a little more:
return budget.save()
.then(res => Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec())
If you need to transform the results returned by findById before turning them over to the client:
return budget.save()
.then(res => Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec())
.then(res => {
res.foo = 'Foo'
return res
})

Related

GraphQL with nested schema returning null

I am trying to return a mongodb document upon a graphql query but getting null value. No error is being shown. The mongodb query works fine with mongoshell or mongoose.
Here is the schema, typedef and resolver:
const unionSchema = new Schema(
{
geometry: mongoose.Schema.Types.MultiPolygon,
properties: {
Divi_name: String,
Dist_name: String,
Upaz_name: String,
Uni_namae: String,
},
},
{ collection: "unionbounds" }
);
const union = mongoose.model("Union", unionSchema);
const typeDefs = `
type Query {
data: Union
}
type Union {
properties: Props
}
type Props{
Dist_name: String,
}
`;
const resolvers = {
Query: {
data: () => {
union.findOne(
{
geometry: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [90, 22],
},
},
},
},
"properties"
);
},
},
};
Mongoshell query returns the document:
{
properties: {
Div_ID: '10',
Dist_ID: '04',
Upz_ID: '28',
Un_ID: '95',
Un_UID: '10042895',
Divi_name: 'Barisal',
Dist_name: 'Barguna',
Upaz_name: 'Barguna Sadar Upazila',
Uni_name: 'Naltona',
Area_SqKm: 45.7658667915
},
_id: 6001e54a51c6d49215322f94
}
My suspicion is that I am doing something wrong in the resolver function. I would appreciate any suggestion.
The problem was indeed the resolver function. Following code worked after returning the result from the callback function and using async .. await.
const resolvers = {
Query: {
data: async () => {
var value;
await union.findOne(
{
geometry: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [90, 22],
},
},
},
},
"properties",
function (err, result) {
value = result;
}
);
return value;
},
},
};

Get all data from subdocument via graphql

Model
const mongoose=require('mongoose');
const CustomerGeneralInformation = require('./CustomerGeneralInformation').schema;
const CustomerContact = require('./CustomerContact').schema;
const CustomerFinance=require('./CustomerFinancial').schema;
const CustomerPersonalData=require('./CustomerPersonalData').schema;
const CustomerIdentification=require('./CustomerIdentification').schema;
const Schema=mongoose.Schema;
const CustomerSchema=new Schema({
generalInformation: [CustomerGeneralInformation],
contactData: [CustomerContact],
financialData:[CustomerFinance],
personalData:[CustomerPersonalData],
identificationData:[CustomerIdentification]
});
module.exports=mongoose.model('Customer',CustomerSchema);
Graphql Schema
const RootQuery=new GraphQLObjectType({
name:'RootQueryType',
fields:{
customers:{
type: new GraphQLList(CustomerType),
resolve(parent,args){
return customer.find({});
}
}
}
});
GraphiQl
{
customers
{
id
generalInformation{
purposeOfBusiness
}
contactData{
phone
email
countryResidence
mailbox
houseNo
zip
city
}
financialData{
taxNo
countryTaxation
refBankIban
StringrefBankBic
refBankIban
}
}
}
Result
{
"data": {
"customers": [
{
"id": "5fa0f8ea4e028a2cf8d24c3f",
"generalInformation": {
"purposeOfBusiness": null
},
"contactData": {
"phone": null,
"email": null,
"countryResidence": null,
"mailbox": null,
"houseNo": null,
"zip": null,
"city": null
},
"financialData": {
"taxNo": null,
"countryTaxation": null,
"refBankIban": null,
"StringrefBankBic": null
}
}
]
}
}
SO I have created a customer model which have an id(autogenerated by mongodb) and 5 other fields of schema type.
I have used graphql for creating apis.
Everything is working fine, I have created mutations to add data, its all tested in mongo that data is being saved.
But if you check my graphql output I am unable to query subdocuments, it shows null. I want list of all subdocuments with data.
PlEASE HELP
I had tried this way and its working perfectly,
Firstly as you are passing the whole model in your new Customer model so instead of that I just have stored the ID as a reference.
const CustomerSchema = new mongoose.Schema(
{
generalInformation: {
type: mongoose.Schema.Types.ObjectId,
ref: "GeneralInfo"
},
contactData: { type: mongoose.Schema.Types.ObjectId, ref: "ContactData" },
financialData: {
type: mongoose.Schema.Types.ObjectId,
ref: "FinacialData"
},
personalData: { type: mongoose.Schema.Types.ObjectId, ref: "PersonalData" }
},
{
timestamps: true
}
);
After that, for CustomerType, I had done this
const CustomerType = new GraphQLObjectType({
name: "Customer",
fields: () => ({
id: { type: GraphQLID },
customerContact: {
type: CustomerContactType,
resolve(parent, args) {
return CustomerContact.findById(parent.contactData);
}
},
generalInformation: {
type: CustomerGeneralType,
resolve(parent, args) {
return CustomerGeneral.findById(parent.generalInformation);
}
},
financialData: {
type: CustomerFinanceType,
resolve(parent, args) {
return CustomerFinance.findById(parent.financialData);
}
},
personalData: {
type: CustomerPersonalType,
resolve(parent, args) {
return CustomerPersonal.findById(parent.personalData);
}
}
})
});
And them for RootQuery
customers: {
type: new GraphQLList(CustomerType),
resolve(parent, args) {
return Customar.find({});
}
}
and here is my Query:
{
customers{
id
generalInformation{
purposeOfBusiness
}
customerContact{
phone
email
countryResidence
}
financialData{
taxNo
}
}
}
And Output
{
"data": {
"customers": [
{
"id": "5fa3fe066f0fda0568e56456",
"generalInformation": {
"purposeOfBusiness": "Test Purpose"
},
"customerContact": {
"phone": "123456798",
"email": "test#demo.com",
"countryResidence": "Pak"
},
"financialData": {
"taxNo": "120033244"
}
}
]
}
}

Create Custom mapping type in Elasticsearch 7.3.2 using node js

When I am doing custom mapping using kibana its working properly but when I am doing the same thing in my node program its showing mapper parsing exception.
Reason:Root mapping definition has unsupported parameters:tags(custom mapping name)
Because in kibana i am able to use include_type_name =true but in my node program it is not available.
var name = req.body.templatename;
var index_patterns = req.body.index_patterns;
console.log(index_patterns);
const opts: IndicesPutTemplateParams = {
name: name,
body: {
index_patterns: [index_patterns],
settings: {
analysis: {
filter: {
autocomplete_filter: {
type: "edge_ngram",
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete: {
type: "custom",
tokenizer: "standard",
filter: [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
mappings: {
tags: {
properties: {
name: {
type: "text",
analyzer: "autocomplete",
search_analyzer: "standard"
},
normalized: {
type: "text"
},
status: {
type: "text"
},
createdat: {
type: "date"
},
updatedat: {
type: "date"
}
}
}
}
}
}
try {
esClient.indices.putTemplate(opts).then((data: any) => {
return res.json({
data
});
console.log(data);
}).catch((err: any) => {
console.log(err);
res.status(500).json({
err
})
});
} catch (error) {
res.status(500).json({
error
})
}
}```
As Per documentation you need to give include_type_name as
client.indices.putTemplate({
name: string,
include_type_name: boolean, --->
order: number,
create: boolean,
timeout: string,
master_timeout: string,
flat_settings: boolean,
body: object -> mapping object
})
Or you can drop mapping name tags from mapping
mappings: {
tags: { ---> remove

mongoDB find, update and pull in One Query

I want to do all the find the data from the collection and then want to update some field as well as depending on want to empty the array.
const addCityFilter = (req, res) => {
if (req.body.aCities === "") {
res.status(409).jsonp({ message: adminMessages.err_fill_val_properly });
return false;
} else {
var Cities = req.body.aCities.split(","); // It will make array of Cities
const filterType = { "geoGraphicalFilter.filterType": "cities", "geoGraphicalFilter.countries": [], "geoGraphicalFilter.aCoordinates": [] };
/** While using $addToset it ensure that to not add Duplicate Value
* $each will add all values in array
*/
huntingModel
.update(
{
_id: req.body.id,
},
{
$addToSet: {
"geoGraphicalFilter.cities": { $each: Cities }
}
},
{$set:{filterType}},
).then(function(data) {
res.status(200).jsonp({
message: adminMessages.succ_cityFilter_added
});
});
}
};
Collection
geoGraphicalFilter: {
filterType: {
type:String,
enum: ["countries", "cities", "polygons"],
default: "countries"
},
countries: { type: Array },
cities: { type: Array },
aCoordinates: [
{
polygons: { type: Array }
}
]
}
But as result, the only city array is getting an update. No changes in filterType.
You appear to be passing the $set of filterType as the options argument, not the update argument.
huntingModel
.update(
{
_id: req.body.id,
},
{
$addToSet: {
"geoGraphicalFilter.cities": { $each: Cities }
},
$set: {
filterType
}
}
).then(function(data) {
res.status(200).jsonp({
message: adminMessages.succ_cityFilter_added
});
});

Unable to fetch list in react relay

I am following schema same as mentioned here
I want to fetch all users so I updated my schema like this
var Root = new GraphQLObjectType({
name: 'Root',
fields: () => ({
user: {
type: userType,
resolve: (rootValue, _) => {
return getUser(rootValue)
}
},
post: {
type: postType,
args: {
...connectionArgs,
postID: {type: GraphQLString}
},
resolve: (rootValue, args) => {
return getPost(args.postID).then(function(data){
return data[0];
}).then(null,function(err){
return err;
});
}
},
users:{
type: new GraphQLList(userType),
resolve: (root) =>getUsers(),
},
})
});
And in database.js
export function getUsers(params) {
console.log("getUsers",params)
return new Promise((resolve, reject) => {
User.find({}).exec({}, function(err, users) {
if (err) {
resolve({})
} else {
resolve(users)
}
});
})
}
I am getting results in /graphql as
{
users {
id,
fullName
}
}
and results as
{
"data": {
"users": [
{
"id": "VXNlcjo1Nzk4NWQxNmIwYWYxYWY2MTc3MGJlNTA=",
"fullName": "Akshay"
},
{
"id": "VXNlcjo1Nzk4YTRkNTBjMWJlZTg1MzFmN2IzMzI=",
"fullName": "jitendra"
},
{
"id": "VXNlcjo1NzliNjcyMmRlNjRlZTI2MTFkMWEyMTk=",
"fullName": "akshay1"
},
{
"id": "VXNlcjo1NzliNjgwMDc4YTYwMTZjMTM0ZmMxZWM=",
"fullName": "Akshay2"
},
{
"id": "VXNlcjo1NzlmMTNkYjMzNTNkODQ0MmJjOWQzZDU=",
"fullName": "test"
}
]
}
}
but If I try to fetch this in view as
export default Relay.createContainer(UserList, {
fragments: {
userslist: () => Relay.QL`
fragment on User #relay(plural: true) {
fullName,
local{
email
},
images{
full
},
currentPostCount,
isPremium,
}
`,
},
});
I am getting error Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.
Please tell me what I am missing .
I tried a lot with and without #relay(plural: true).
Also tried to update schema with arguments as
users:{
type: new GraphQLList(userType),
args: {
names: {
type: GraphQLString,
},
...connectionArgs,
},
resolve: (root, {names}) =>connectionFromArray(getUsers(names)),
},
but I got error Cannot read property 'after' of undefined in implementing react-relay
Thanks in Advance.
Relay currently only supports three types of root fields (see facebook/relay#112):
Root field without arguments, returning a single node:
e.g. { user { id } } returning {"id": "123"}
Root field with one argument, returning a single node:
e.g. { post(id: "456") { id } } returning {"id": "456"}
Root field with one array argument returning an array of nodes with the same size as the argument array (also known as "a plural identifying root field"):
e.g. { users(ids: ["123", "321"]) { id } } returning [{"id": "123"}, {"id": "321"}]
A workaround is to create a root field (often called viewer) returning a node that has those fields. When nested inside the Viewer (or any other node), fields are allowed to have any return type, including a list or connection. When you've wrapped the fields in this object in your GraphQL server, you can query them like this:
{
viewer {
users {
id,
fullName,
}
}
}
The Viewer type is a node type, and since there will just be one instance of it, its id should be a constant. You can use the globalIdField helper to define the id field, and add any other fields you want to query with Relay:
const viewerType = new GraphQLObjectType({
name: 'Viewer',
interfaces: [nodeInterface],
fields: {
id: globalIdField('Viewer', () => 'VIEWER_ID'),
users:{
type: new GraphQLList(userType),
resolve: (viewer) => getUsers(),
},
},
});
On the client you'll need to change the root query in your route to { viewer } and define the fragment on Viewer:
export default Relay.createContainer(UserList, {
fragments: {
viewer: () => Relay.QL`
fragment on Viewer {
users {
fullName,
local {
email,
},
images {
full,
},
currentPostCount,
isPremium,
}
}
`,
},
});

Resources