GraphQL + Mongoose: How to change property of mongoose retrieved data - javascript

I'm writing a GraphQL query that will return mongoose data:
export const getInventory = () => {
let query = {
deletedAt: null
};
let stocks = await StockModel.find(query)
.sort({ material: 1 });
// Now separate each inventory item per material
let inventory = {};
stocks.map(stock => {
if (inventory[stock.material]) {
inventory[stock.material].quantity += stock.quantity;
} else {
let clone = Object.assign({}, stock);
clone.lot = null;
clone.expirationDateTime = null;
clone.partNumber = null;
clone.manufacturer = null;
inventory[stock.material] = clone;
}
});
let list = Object.keys(inventory).map(key => {
return inventory[key];
});
return list;
};
Here is my inventory GraphQL query:
const inventory = {
type: new GraphQLList(StockType),
description: "Get all inventory",
resolve(root, args, context) {
return getInventory();
}
};
When running the following query:
{
viewer {
inventory() {
id
quantity
lot
}
}
}
I'm getting the following GraphQL error:
{
"errors": [
{
"message": "Expected value of type \"Stock\" but got: [object Object].",
"locations": [
{
"line": 3,
"column": 5
}
],
"stack": "Expected value of type \"Stock\" but got: [object Object].\n\nGraphQL request (3:5)\n2: viewer {\n3: inventory {\n ^\n4: id\n\n at invalidReturnTypeError (/dev/node_modules/graphql/execution/execute.js:766:10)\n at completeObjectValue (/dev/node_modules/graphql/execution/execute.js:758:13)\n at completeValue (/dev/node_modules/graphql/execution/execute.js:660:12)\n at completeValueWithLocatedError (/dev/node_modules/graphql/execution/execute.js:580:21)\n at completeValueCatchingError (/dev/node_modules/graphql/execution/execute.js:556:21)\n at /dev/node_modules/graphql/execution/execute.js:684:25\n at Array.forEach (<anonymous>)\n at forEach (/dev/node_modules/iterall/index.js:83:25)\n at completeListValue (/dev/node_modules/graphql/execution/execute.js:680:24)\n at completeValue (/dev/node_modules/graphql/execution/execute.js:643:12)\n at /dev/node_modules/graphql/execution/execute.js:617:14\n at process._tickCallback (internal/process/next_tick.js:68:7)",
"path": [
"viewer",
"inventory",
0
]
}
}
How can I solve the error?

Related

how to optimize code like reduce code with same functionality

let response = {};
var filters = {
topfeaturedandotherfields: req.body.topfeaturedandotherfields,
};
if (req.body.minprice && req.body.maxprice && req.body.brandName) {
var filters = {
$and: [
{ brandName: { $in: req.body.brandName } },
{ topfeaturedandotherfields: req.body.topfeaturedandotherfields },
{ salePrice: { $gte: req.body.minprice, $lte: req.body.maxprice } },
],
};
var result = await productService.getAllProductofhomepage(
filters,
req.body.ordername,
req.body.orderby
);
} else {
if (req.body.minprice && req.body.maxprice) {
var filters = {
$and: [
{ topfeaturedandotherfields: req.body.topfeaturedandotherfields },
{ salePrice: { $gte: req.body.minprice, $lte: req.body.maxprice } },
],
};
var result = await productService.getAllProductofhomepage(
filters,
req.body.ordername,
req.body.orderby
);
}
if (req.body.brandName) {
var filters = {
$and: [
{ brandName: { $in: req.body.brandName } },
{ topfeaturedandotherfields: req.body.topfeaturedandotherfields },
],
};
var result = await productService.getAllProductofhomepage(
filters,
req.body.ordername,
req.body.orderby
);
}
}
if (req.body.limit == true)
var result = await productService.getAllProductofhomepagewithlimit(filters);
else if (req.body.minprice || req.body.maxprice || req.body.brandName) {
} else {
var result = await productService.getAllProductofhomepage(
filters,
req.body.ordername,
req.body.orderby
);
}
if (result.length > 0) {
response = {
message: "Home page products successfully retrieved",
error: false,
data: result,
};
} else {
response = {
message: "Faild to get products",
error: true,
data: {},
};
}
res.status(200).json(response);
This code is used to filter like to see top feature and bestseller or min and max price and the brand name also in this code sort by order name which could be price or brand name or category also in ascending and descending order so now you can see this code is like if and else but I want to optimize and reduce code
You can make this query quite a lot nicer by just dynamically building the query condition instead of breaking the logic into if/else blocks:
export async function login(req: Request, res: Response): Promise<void> {
const response = {};
let filters = {
topfeaturedandotherfields: req.body.topfeaturedandotherfields,
};
if (req.body.minprice || req.body.maxprice) {
const saleCond = { };
if (req.body.minprice) {
saleCond.$gte = req.body.minprice;
}
if (req.body.maxprice) {
saleCond.$lte = req.body.maxprice;
}
filters.salePrice = saleCond
}
if (req.body.brandName) {
filters.brandName = {$in: req.body.brandName}
}
let result = [];
if (req.body.limit == true) {
result = await productService.getAllProductofhomepagewithlimit(filters)
} else {
result = await productService.getAllProductofhomepage(filters, req.body.ordername, req.body.orderby);
}
res.status(200).json({
message: result.length ? 'Home page products successfully retrieved' : 'Failed to get products',
error: result.length === 0,
data: result,
});
}
Not only is this much clearer we only removed a redundant DB call that was made in the process.

GAPI Export to Google Sheet Invalid Argument Error

I'm trying to export details from out app into a google sheet and am getting an "Invalid argument" error. I'm trying to take the data from the page and also grab users' birthdays on export. We use firestore as a db.
exportStaff(shift) {
console.log(shift)
const exportHeaders = [
"Day",
"Event",
"Position",
"Start",
"End",
"First Name",
"Last Name",
"Phone",
"Email",
"Confirmed",
"DOB",
"Code",
];
const exportItems = [];
for (var key in this.orderedPlacedUsers2(shift.id)) {
function myDOB(staff) {
return fb.usersCollection.doc(staff).get()
.then(doc => {
console.log(doc.data().dob)
return doc.data().dob
})
}
exportItems.push([
shift.day,
shift.event,
shift.position.title,
shift.startTime,
shift.endTime,
this.orderedPlacedUsers2(shift.id)[key].firstName,
this.orderedPlacedUsers2(shift.id)[key].lastName,
this.orderedPlacedUsers2(shift.id)[key].phone,
this.orderedPlacedUsers2(shift.id)[key].email,
this.orderedPlacedUsers2(shift.id)[key].confirmed,
myDOB(this.orderedPlacedUsers2(shift.id)[key].userId),
`=REGEXEXTRACT(H2,"....$")`
])
}
this.$gapi.getGapiClient().then(gapi => {
const exportService = new ExportService(exportHeaders, Object.values(exportItems), gapi);
exportService.export();
});
},
All of the birthdays are logging correctly to the console, but no values show on the sheet.
Here is a screenshot of the error in the console.
How can I get the birthdays (DOB) to export properly?
Here is my exportService.js
export default class ExportService {
constructor(columns, data, gapi) {
this.columns = columns;
this.data = data;
this.gapi = gapi;
this.spreadsheetId = null;
}
export() {
this.gapi.auth2.getAuthInstance().signIn()
.then(() => {
this.createSpreadsheet();
});
}
createSpreadsheet() {
this.gapi.client.sheets.spreadsheets.create({
properties: {
title: 'New Report'
}
}).then((response) => {
this.spreadsheetId = response.result.spreadsheetId;
this.writeRows();
this.openSpreadsheet(response.result.spreadsheetUrl)
});
}
writeRows() {
this.data.unshift(this.columns);
this.gapi.client.sheets.spreadsheets.values.append({
spreadsheetId: this.spreadsheetId,
range: 'A1:F1',
valueInputOption: 'USER_ENTERED',
resource: {
values: this.data
}
}).then((response) => {
var result = response.result;
console.log(`${result.updates.updatedCells} cells appended.`)
});
}
openSpreadsheet(url) {
window.open(url, '_blank');
}
}

parsing HashMap failed, expected Object, but encountered Array

For creating an action at hasura I'm using the following node.js code (still at an experimental stage) in glitch.com -
const execute = async (gql_query, variables) => {
const fetchResponse = await fetch(
"https://example.com/v1/graphql",
{
method: "POST",
body: JSON.stringify({
query: gql_query,
variables: variables
})
}
);
// console.log('DEBUG: ', fetchResponse);
const data = await fetchResponse.json();
console.log("DEBUG: ", data);
return data;
};
// paste the code from codegen here
const ACTION_INSERT_PAYSLIP_GET_DRIVER_PAYMENT_DATA = `
query getDriverPaymentData ($orders: [Int!]!) {
company_order (where: {company_order_id: {_in: $orders}}) {
company_order_details (distinct_on: stage_cost_driver_id) {
stage_cost_driver_id
company_user {
delivery_salary
}
}
}
}`
// Request Handler
app.post('/action_insert_payslip', async (req, res) => {
// get request input
const { order_list } = req.body.input
console.log('Input', order_list)
const orders = order_list.order_id
console.log('Item: ', orders)
const { data:driverPaymentData, errors:driverPaymentError} = await execute(ACTION_INSERT_PAYSLIP_GET_DRIVER_PAYMENT_DATA, orders)
console.log('Driver Payment Data: ', driverPaymentData)
// run some business logic
// success
return res.json({
// payslip_list: "<value>"
payslip_list: order_list
})
});
The query getDriverPaymentData produces an output like the following in hasura api explorer:
{
"data": {
"company_order": [
{
"company_order_details": [
{
"stage_cost_driver_id": 1,
"company_user": {
"delivery_salary": 20
}
},
{
"stage_cost_driver_id": 6,
"company_user": {
"delivery_salary": 10
}
}
]
},
{
"company_order_details": [
{
"stage_cost_driver_id": 6,
"company_user": {
"delivery_salary": 10
}
}
]
}
]
}
}
But in the log, I'm getting the following output:
Input { order_id: [ 247, 260, 253 ] }
Item: [ 247, 260, 253 ]
DEBUG: { errors:
[ { extensions: [Object],
message:
'parsing HashMap failed, expected Object, but encountered Array' } ] }
Driver Payment Data: undefined
It says that it expects object but encountered array. But from what I see, I'm already getting an object "data": {[....]} with array inside it from the output at hasura's API console.
What am I missing here? How can I get the data of stage_cost_driver_id and delivery_salary?
Shouldn't variables be an object?
body: JSON.stringify({
query: gql_query,
variables: {orders: variables}
})

method is returning id but not saving other data points

My method works when I put values in new Farm () but not when I run it through postman in JSON which is also displayed below. I do not think I am parsing the JSON incorrectly. Any suggestions would be appreciated ?
export interface IDataFlowService {
handle(request: IDataFlowRequest): Promise<IDataFlowResponse>;
}
export class DataFlowService implements IDataFlowService {
current_env = process.env.NODE_ENV;
async handle(request: IDataFlowRequest): Promise<IDataFlowResponse> {
let response: IDataFlowResponse;
try {
switch (request.requestType) {
case "SaveFarms":
response = await this.SaveFarms(request);
break;
default:
winston.error(`Request failed for request type: ${request.requestType}`);
break;
}
return response;
} catch (e) {
winston.error(`handle method failed for request: ${request}`, e);
response = {
success: false,
error: {
'message': e.message,
}
};
return response;
}
}
private async SaveFarms(request: IDataFlowRequest): Promise<IDataFlowResponse> {
const response: IDataFlowResponse = {
success: true ,
farmIds: [],
names: []
};
for (const farm of request.farms) {
const newFarm: IFarmModel = new Farm();
Promise.all([newFarm.save()]);
response.farmIds.push(newFarm.farmId) ;
response.names.push(newFarm.name) ;
}
return response;
}
}
here is post: http://localhost:5000/api/dataflow
{
"requestType":"SaveFarms",
"farms": [
{
"name" : "Bronx"
}
]
}
as you can see I get a response but the names field is coming back null/empty:
{
"success": true,
"farmIds": [
"fH1WjllXR"
],
"names": [
null
]
}
You forget set name for newFarm object:
const newFarm: IFarmModel = new Farm();
newFarm.name = farm.name; // I think so

Export table values Meteor Blaze

I am running into some difficulty exporting a table to csv in meteor/blaze. I am following: [http://rafaelquintanilha.com/export-your-json-data-to-csv-format/][1].
I have a Template.event that is triggering the export button
Template.export.onCreated( () => {
Template.instance().subscribe('table');
});
Template.export.helpers({
exportContacts() {
return Contacts.find();
}
});
Template.export.events({
'click .export-data' () {
MyAppExporter.exportAllContacts();
}
});
it is calling exportAllContacts() in a global helper
MyAppExporter = {
exportAllContacts: function() {
var self = this;
Meteor.call("exportContacts", function(error, data) {
if ( error ) {
alert(error);
return false;
}
var csv = Papa.unparse(data);
self._downloadCSV(csv);
});
},
_downloadCSV: function(csv) {
var blob = new Blob([csv]);
var a = window.document.createElement("a");
a.href = window.URL.createObjectURL(blob, {type: "text/plain"});
a.download = "contacts.csv";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
and the helper is calling a Meteor.method exportContacts
Meteor.methods({
exportContacts: function() {
let fields = [
"Email",
“Some Contact",
"Created Date",
"Hard Bounce",
"Unsubscribed"
];
let data = [];
let contacts = Contacts.find().fetch();
for(let i = 0; i < contacts.length; i++) {
let contact = contacts[i];
let contactString = JSON.stringify(contact);
_.each(contactString, function(c) {
console.log("Inside Loop", contactString);
data.push([
c.contact.emailAddress,
c.contact.someContact,
c.contact.creationDate,
c.contact.hardBounceBack,
c.contact.unsubscribed
]);
console.log("DATA", data)
return {fields: fields, data: data};
});
}
}
});
I keep getting an error that “emailAddress is not defined exportContacts.js:20:17
20160426-22:00:47.957(-4)? Inside Loop {"_id":"dRnXRdZrbR9CYdmBx","contact":[{"emailAddress":"fred#weasly.com","someContact":"No","creationDate":"N/A","hardBounceBack":"N/A","unsubscribed":"N/A"}]}
I20160426-22:00:48.029(-4)? Exception while invoking method 'exportContacts' ReferenceError: emailAddress is not defined
I20160426-22:00:48.029(-4)? at server/methods/exportContacts.js:20:17
I20160426-22:00:48.029(-4)? at Function._.each._.forEach (packages/underscore.js:142:22)
I20160426-22:00:48.029(-4)? at _loop (server/methods/exportContacts.js:17:7)
but I cannot seem to figure out how to access the contacts. I am logging it out (see above in logs). Any help would be appreciated.
ADDED LOGS
let contacts = Contacts.find().fetch(); console.log(contacts)
I20160427-09:06:23.484(-4)? CONTACTS [ { _id: 'dRnXRdZrbR9CYdmBx', contact: [ [Object] ] },
I20160427-09:06:23.484(-4)? { _id: 'LHmW4R9PLM5D7cZxr', contact: [ [Object] ] },
I20160427-09:06:23.484(-4)? { _id: 'jBdqQXz2b8itXJowX', contact: [ [Object] ] },
I20160427-09:06:23.484(-4)? { _id: 'bnDvNGX3i879z4wr2', contact: [ [Object] ] } ]
c.contact[0].emailAddress logged out
I20160427-09:22:08.142(-4)? Inside Loop {"_id":"dRnXRdZrbR9CYdmBx","contact":[{"emailAddress":"fred#weasly.com","someContact":"No","creationDate":"N/A","hardBounceBack":"N/A","unsubscribed":"N/A"}]}
I20160427-09:22:08.217(-4)? Exception while invoking method 'exportContacts' TypeError: Cannot read property '0' of undefined
I20160427-09:22:08.217(-4)? at server/methods/exportContacts.js:21:7
I20160427-09:22:08.217(-4)? at Function._.each._.forEach (packages/underscore.js:142:22)
I20160427-09:22:08.217(-4)? at _loop (server/methods/exportContacts.js:18:7)
I20160427-09:22:08.218(-4)? at [object Object].exportContacts (server/methods/exportContacts.js:15:46)
Within the _.each loop you are accessing the wrong data items. You can also use a _.each loop instead of the outer for loop too. If you do :
let contacts = Contacts.find().fetch();
_.each(contacts, function(contact) {
_each(contact.contact, function(c) {
data.push(
{
"email": c.emailAddress,
"contact": c. someContact,
"creationDate" : c.creationDate,
"bounceBack": c.hardBounceBack,
"unsubscribed": c.unsubscribed
}
})
})
This should solve your problem. This way you are looping through the outer contacts that is coming back from the fetch and then looping through the contact array from each element. This should be the most direct way to get down to the data you are looking for.
Your problem is this line: _.each(contactString, function(c) {
It should read: _.each(contact, function(c) {
:)

Categories