I am trying to create a journal entry on NetSuite using its SuiteScript API.
Here is my code.
export function post() {
var rec = record.create({
type: record.Type.JOURNAL_ENTRY,
isDynamic: true,
});
rec.setValue({
fieldId: "memo",
value: "from api ",
});
rec.setValue({
fieldId: "type",
value: "Journal",
});
rec.setText({
fieldId: "type",
text: "Journal",
});
rec.setValue({ fieldId: "transactionnumber", value: "158" });
rec.setValue({ fieldId: "subsidiary", value: "2" });
rec.setText({ fieldId: "subsidiary", text: "Headquarters : United States" });
rec.setValue({ fieldId: "postingperiod", value: "238" });
rec.setText({ fieldId: "postingperiod", text: "Dec 2021" });
rec.setValue({ fieldId: "customform", value: "30" });
rec.setText({ fieldId: "customform", text: "Standard Journal Entry" });
rec.setValue({ fieldId: "exchangerate", value: "1.00" });
//-------------------------debit------------------------------------------
//start a new line
rec.selectNewLine({
sublistId: "line",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account",
value: "1",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "accounttype",
value: "AcctRec",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account_display",
value: "1100 Accounts Receivable",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "debit",
value: "200",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "credit",
value: "",
});
//close of line
rec.commitLine({
sublistId: "line",
});
//----------------------------credit---------------------------------------
//new line again
rec.selectNewLine({
sublistId: "line",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account",
value: "10",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "accounttype",
value: "OthCurrAsset",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account_display",
value: "1200 Inventory",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "credit",
value: "200",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "debit",
value: "",
});
rec.commitLine({
sublistId: "line",
});
var recordId = rec.save();
//-------------------------------------------------------------------
return JSON.stringify(recordId);
}
Everything looks good for me but I am getting the following error
{
"error": {
"code": "INVALID_FLD_VALUE",
"message": "{\"type\":\"error.SuiteScriptError\",\"name\":\"INVALID_FLD_VALUE\",\"message\":\"You have entered an Invalid Field Value 1 for the following field: account\",\"stack\":[\"anonymous(N/serverRecordService)\",\"post(/SuiteScripts/ssv2/journal_restlet.js:73)\"],\"cause\":{\"type\":\"internal error\",\"code\":\"INVALID_FLD_VALUE\",\"details\":\"You have entered an Invalid Field Value 1 for the following field: account\",\"userEvent\":null,\"stackTrace\":[\"anonymous(N/serverRecordService)\",\"post(/SuiteScripts/ssv2/journal_restlet.js:73)\"],\"notifyOff\":false},\"id\":\"\",\"notifyOff\":false,\"userFacing\":false}"
}
}
Basically which means the account value 1 which I m sending to create line is invalid. But 1 is a valid account id of a Cash account.
This is the response of lines when I call get method.
{
"line": [
{
"scheduletype": "",
"oldstartdate": "",
"entity_display": "",
"memo": "",
"residual": "",
"account_cur": "",
"amortermsrc": "",
"startdate": "",
"tax1acct": "",
"account_cur_fx": "F",
"cleareddate": "",
"custcol_adjustment_tax_code": "",
"grossamt": "",
"custcol_2663_isperson": false,
"credit": "",
"origdebit": 5000,
"item": "",
"sys_parentid": "2040634920479734",
"tax1amt": "",
"amortizationtype": "",
"entity2": "",
"custcol_emirate": "",
"enddate": "",
"entitytype": "Entity",
"lineuniquekey": "89669",
"hasimmutableamortization": false,
"taxcode": "",
"taxcode_display": "",
"custcol_2663_eft_file_format": "",
"cleared": "F",
"line": 0,
"accounttype": "AcctRec",
"kpayitem": "",
"timelineid": "",
"eliminate": false,
"custcol_adjustment_field": "",
"accounteliminate": "F",
"class_display": "",
"giftcertcode": "",
"origcredit": "",
"sys_id": "2040634962802984",
"account_display": "1100 Accounts Receivable",
"btoach": false,
"custcol_2663_lastname": "",
"debit": 5000,
"department": "",
"oldresidual": "",
"class": "",
"ritemcount": "",
"oldenddate": "",
"custcol_2663_firstname": "",
"custcol_far_trn_relatedasset": "",
"department_display": "",
"location_display": "",
"schedule": "",
"schedulenum": "",
"taxrate1": "",
"custcol_2663_companyname": "",
"location": "",
"entity_cur": "",
"account": "6",
"entity": ""
},
{
"scheduletype": "",
"oldstartdate": "",
"entity_display": "",
"memo": "",
"residual": "",
"account_cur": "",
"amortermsrc": "",
"startdate": "",
"tax1acct": "",
"account_cur_fx": "F",
"cleareddate": "",
"custcol_adjustment_tax_code": "",
"grossamt": "",
"custcol_2663_isperson": false,
"credit": 5000,
"origdebit": "",
"item": "",
"sys_parentid": "2040634920479734",
"tax1amt": "",
"amortizationtype": "",
"entity2": "",
"custcol_emirate": "",
"enddate": "",
"entitytype": "Entity",
"lineuniquekey": "89670",
"hasimmutableamortization": false,
"taxcode": "",
"taxcode_display": "",
"custcol_2663_eft_file_format": "",
"cleared": "F",
"line": 1,
"accounttype": "OthCurrAsset",
"kpayitem": "",
"timelineid": "",
"eliminate": false,
"custcol_adjustment_field": "",
"accounteliminate": "F",
"class_display": "",
"giftcertcode": "",
"origcredit": 5000,
"sys_id": "2040634962760922",
"account_display": "1200 Inventory",
"btoach": false,
"custcol_2663_lastname": "",
"debit": "",
"department": "",
"oldresidual": "",
"class": "",
"ritemcount": "",
"oldenddate": "",
"custcol_2663_firstname": "",
"custcol_far_trn_relatedasset": "",
"department_display": "",
"location_display": "",
"schedule": "",
"schedulenum": "",
"taxrate1": "",
"custcol_2663_companyname": "",
"location": "",
"entity_cur": "",
"account": "10",
"entity": ""
}
],
"recmachcustrecord109": [],
"recmachcustrecord_2663_parent_bill": [],
"recmachcustrecord_2663_parent_payment": [],
"recmachcustrecord_2663_transaction": [],
"recmachcustrecord_assetsourcetrn": [],
"recmachcustrecord_deprhistjournal": [],
"recmachcustrecord_far_expinc_transaction": [],
"recmachcustrecord_nsts_rfc_created_trans": [],
"recmachcustrecord_nsts_rfc_related_records": [],
"recmachcustrecord_summary_histjournal": [],
"recmachcustrecord_wmsse_order_no": [],
"recmachcustrecord_wmsse_order_no_clt": [],
"recmachcustrecord_wmsse_ordno": [],
"recmachcustrecord_wmsse_parent_orderno": [],
"recmachcustrecord_wmsse_ship_order": [],
"activities": [],
"mediaitem": [],
"usernotes": [],
"links": [],
"systemnotes": [],
"calls": [],
"tasks": [],
"events": []
}
Here account ids are 6 and 10. I still get the same error even I use 6 and 10 in the account fields. Does anyone know how to solve this issue?
Thanks,
Krishna
The problem was subsidiary and my account ids were not matching. Here is the complete code if someone needs it in the future.
export function post() {
var rec = record.create({
type: record.Type.JOURNAL_ENTRY,
isDynamic: true,
});
rec.setValue({
fieldId: "memo",
value: "from api ",
});
rec.setValue({
fieldId: "type",
value: "Journal",
});
rec.setText({
fieldId: "type",
text: "Journal",
});
// rec.setValue({ fieldId: "transactionnumber", value: "158" });
rec.setValue({ fieldId: "subsidiary", value: "2" });
rec.setText({ fieldId: "subsidiary", text: "Headquarters : United States" });
rec.setValue({ fieldId: "postingperiod", value: "238" });
rec.setText({ fieldId: "postingperiod", text: "Dec 2021" });
rec.setValue({ fieldId: "trandate", value: new Date("12/27/2021") });
// rec.setValue({ fieldId: "customform", value: "30" });
// rec.setText({ fieldId: "customform", text: "Standard Journal Entry" });
rec.setValue({ fieldId: "exchangerate", value: "1.00" });
//-------------------------debit------------------------------------------
//start a new line
rec.selectNewLine({
sublistId: "line",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account",
value: 363,
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "accounttype",
value: "AcctRec",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account_display",
value: "1100 Accounts Receivable",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "debit",
value: "200",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "credit",
value: "",
});
//close of line
rec.commitLine({
sublistId: "line",
});
//----------------------------credit---------------------------------------
//new line again
rec.selectNewLine({
sublistId: "line",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account",
value: 10,
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "accounttype",
value: "OthCurrAsset",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account_display",
value: "1200 Inventory",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "credit",
value: "200",
});
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "debit",
value: "",
});
rec.commitLine({
sublistId: "line",
});
var recordId = rec.save();
//-------------------------------------------------------------------
return JSON.stringify(recordId);
}
I guess its throwing an error because you are passing the account value as a string.
Try this -
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account",
value: Number(1) //Change this
});
Let me know in case of any issues.
It looks like you are trying to set the account using the account name or account number rather than the account internal id. The setCurrentSublistValue call, when dealing with a linked record like this, needs the internal ID, not the name or number:
rec.setCurrentSublistValue({
sublistId: "line",
fieldId: "account_display",
value: "{internalid of account}",
});
EDIT: Assuming here that you mean to use SuiteScript 2.0, since that's the code you wrote, and not SuiteTalk, which is different code altogether.
Related
I have a json data like this.
[{
"name": "Peter",
"age": 30,
"hair color": "brown"
}, {
"name": "Steve",
"age": 55,
"hair color": "blonde"
}, {
"name": "Steve",
"age": 25,
"hair color": "black"
}]
My code it does is, It will identify the duplicate and remove the second occurrence.
The code is :
var qdata = [{
"name": "Peter",
"age": 30,
"hair color": "brown"
}, {
"name": "Steve",
"age": 55,
"hair color": "blonde"
}, {
"name": "Steve",
"age": 25,
"hair color": "black"
}]
data = qdata.filter((obj, pos, arr) => {
return arr.map(mapObj =>
mapObj.name).indexOf(obj.name) == pos;
});
console.log(data);
Output will be :
[
{ name: 'Peter', age: 30, 'hair color': 'brown' },
{ name: 'Steve', age: 55, 'hair color': 'blonde' }
]
Here it deletes the second occurrence and keeps the first one, But what I would like to get is remove the first occurrence and keep the second one
[
{ name: 'Peter', age: 30, 'hair color': 'brown' },
{ name: 'Steve', age: 25, 'hair color': 'black' }
]
How can I do that ? Please help
You can simply reverse the array and do what you want and reverse the result to match with your expected result.
qdata.reverse();
data = qdata.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj.name).indexOf(obj.name) == pos;
});
console.log(data.reverse());
if you don't want to do that you can use the below code to get desired result.
data = [];
qdata.map((i) => {
index = data.findIndex((u) => u.name === i.name);
if (index >= 0) {
data.splice(index, 1, i);
} else {
data.push(i);
}
});
console.log(data);
I am trying to get values to a JSON file, based on field mapping from another JSON file.
I have a JSON file I get from external systems, which have different field names. I created a JSON file that will map the fields from the external system to the names I need the fields to be in:
{
"username":"user",
"externalSystemId":"id",
"active":"active",
"type":"type",
"patronGroup":"group",
"meta": {
"creation_date":"dateCreated",
"last_login_date":"lastLogin"
},
"personal": {
"lastName":"lname",
"firstName":"fname",
"email":"email",
"phone":"phone",
"mobilePhone":"mobile",
"dateOfBirth":"birthDate",
"addresses":{
"countryId": "countryCode",
"addressLine1": "address",
"addressLine2": "address2",
"city": "city",
"region": "region",
"postalCode": "zipcode",
"addressTypeId": "addressType",
"primaryAddress": "primary"
}
},
"enrollmentDate": "enrollmentDate",
"expirationDate": "expirationDate"
}
In this file, the fields are the fields I will need to populate, while the values are the names of the fields I get from the external system, which looks like this for example:
{
"user":"name",
"id":12345,
"active":true,
"type":"Student",
"group":"BA",
"dateCreated":"NOV 22 2019",
"lastLogin":"NOV 23 2020",
"lname":"Yard",
"fname":"Paul",
"email":"email#gmail.com",
"phone":"(000)-000-0000",
"mobile":"(000)-000-0000",
"birthDate":"OCT 11 1999",
"countryId": "US",
"addressLine1": "4th street",
"addressLine2": "25B",
"city": "NY",
"region": "NY",
"postalCode": "00000",
"addressTypeId": "Personal",
"primaryAddress": true,
"enrollmentDate": "MAR 22 2019",
"expirationDate": "MAR 21 2022"
}
So the end JSON file will need to look like this:
{
"username":"name",
"externalSystemId":12345,
"active":true,
"type":"Student",
"patronGroup":"BA",
"meta": {
"creation_date":"NOV 22 2019",
"last_login_date":"NOV 23 2020"
},
"personal": {
"lastName":"Yard",
"firstName":"Paul",
"email":"email#gmail.com",
"phone":"(000)-000-0000",
"mobilePhone":"(000)-000-0000",
"dateOfBirth":"OCT 11 1999",
"addresses":{
"countryId": "US",
"addressLine1": "4th street",
"addressLine2": "25B",
"city": "NY",
"region": "NY",
"postalCode": "00000",
"addressTypeId": "Personal",
"primaryAddress": true
}
},
"enrollmentDate": "MAR 22 2019",
"expirationDate": "MAR 21 2022"
}
I was thinking of using a dictionary/index to create this, but I've never done that before, nor am I sure how to do it.
Is there a simple way to do it?
This kind of mapping is easy with a dictionary when we have single level of JSON.
For a multi level JSON, we can make use of a recursive function to map the data from dictionary.
In the code lets say this is your JSON:
let json = {
username: "user",
externalSystemId: "id",
active: "active",
type: "type",
patronGroup: "group",
meta: {
creation_date: "dateCreated",
last_login_date: "lastLogin",
},
personal: {
lastName: "lname",
firstName: "fname",
email: "email",
phone: "phone",
mobilePhone: "mobile",
dateOfBirth: "birthDate",
addresses: {
countryId: "countryCode",
addressLine1: "address",
addressLine2: "address2",
city: "city",
region: "region",
postalCode: "zipcode",
addressTypeId: "addressType",
primaryAddress: "primary",
},
},
enrollmentDate: "enrollmentDate",
expirationDate: "expirationDate",
};
// Here is the dictionary:
// Note: the personal address field had incorrect mapping for few fields, I have modified the property to match the value of respective key of the JSON.
let dictionary = {
user: "name",
id: 12345,
active: true,
type: "Student",
group: "BA",
dateCreated: "NOV 22 2019",
lastLogin: "NOV 23 2020",
lname: "Yard",
fname: "Paul",
email: "email#gmail.com",
phone: "(000)-000-0000",
mobile: "(000)-000-0000",
birthDate: "OCT 11 1999",
countryCode: "US",
address: "4th street",
address2: "25B",
city: "NY",
region: "NY",
zipcode: "00000",
addressType: "Personal",
primary: true,
enrollmentDate: "MAR 22 2019",
expirationDate: "MAR 21 2022",
};
// recursive function to map the JSON, extract the actual value from from dictionary
function buildMapping(jsonParam) {
let result = {};
// iterate over the JSON parameter
for (const [key, value] of Object.entries(jsonParam)) {
if (typeof value === "object") {
// for type as object, make a recursive call with the object value as param
// collect the result of inner object
let resultInner = buildMapping(value);
// attach the result of the inner object to its key
result[key] = resultInner;
} else {
// check if the dictionary contains the mapping, otherwise set as null
result[key] = dictionary.hasOwnProperty(value)
? dictionary[value]
: null;
}
}
return result;
}
let resultJson = buildMapping(json);
console.log(resultJson);
Result:
{
username: "name",
externalSystemId: 12345,
active: true,
type: "Student",
patronGroup: "BA",
meta: { creation_date: "NOV 22 2019", last_login_date: "NOV 23 2020" },
personal: {
lastName: "Yard",
firstName: "Paul",
email: "email#gmail.com",
phone: "(000)-000-0000",
mobilePhone: "(000)-000-0000",
dateOfBirth: "OCT 11 1999",
addresses: {
countryId: "US",
addressLine1: "4th street",
addressLine2: "25B",
city: "NY",
region: "NY",
postalCode: "00000",
addressTypeId: "Personal",
primaryAddress: true,
},
},
enrollmentDate: "MAR 22 2019",
expirationDate: "MAR 21 2022",
};
I try to implement my first mongoose based REST API.
I tried now for days but cannot get this up and running. I would like to save the survey with an array of controls and for each control an array of controlProperties.
In different scenarios I got it to save survey with controls array but without controlProperties and sometime with not even controls array.
Can someone please help me understand my error?
Thanks a lot.
The structure is as follows:
Survey
-- Array of control
-- Array of controlProperty
My schema files are:
survey.js
const mongoose = require('mongoose');
const Control = require('./control');
const surveySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
min: 4,
max: 255
},
description: {
type: String,
required: false,
max: 1000
},
closeDate: {
type: Date,
required: false
},
controls: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Control' }]
});
module.exports = mongoose.model('Survey', surveySchema);
control.js
const mongoose = require('mongoose');
const Survey = require('./survey');
const controlSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
survey: {type: mongoose.Schema.Types.ObjectId, ref: 'Survey'},
controlType: {
type: String,
required: true
},
name: {
type: String,
required: true
},
isInput: {
type: Boolean,
required: true
},
order: {
type: Number,
required: true
},
controlProperties: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ControlProperty' }]
});
module.exports = mongoose.model('Control', controlSchema);
controlProperty.js
const mongoose = require('mongoose');
const Control = require('./control');
mongoose.Schema.Types.String.checkRequired(v => v != null);
const controlPropertySchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
control: { type: mongoose.Schema.Types.ObjectId, ref: 'Control' },
propertyName: {
type: String,
required: true
},
propertyValue: {
type: String,
required: true
},
order: {
type: Number,
required: true
}
})
module.exports = mongoose.model('ControlProperty', controlPropertySchema);
My node.js code to receive the post data is this one:
/routes/survey.js
router.post("/", (req, res, next) => {
Survey.find({ _id: req.body._id })
.exec()
.then(result => {
if (result.length >= 1) {
return res.status(409).json({
message: "Survey exists"
});
} else {
const survey = new Survey({
_id: new mongoose.Types.ObjectId(),
name: req.body.name,
description: req.body.description,
closeDate: req.body.closeDate,
order: req.body.order
});
let controlData = req.body.controls;
let arControls = [];
if(controlData != null) {
for (var i = 0, clen = controlData.length; i < clen; i++) {
let c = controlData[i];
let control = new Control({
_id: new mongoose.Types.ObjectId(),
controlType: c.controlType,
name: c.name,
isInput: c.isInput,
order: c.order
})
let controlPropertyData = c.controlProperties;
let arControlProperty = [];
if(controlPropertyData != null) {
for (var j = 0, cplen = controlPropertyData.length; j < cplen; j++) {
let cp = controlPropertyData[j];
let controlProperty = new ControlProperty({
_id: new mongoose.Types.ObjectId(),
propertyName: cp.propertyName,
propertyValue: cp.propertyValue,
order: cp.order
})
arControlProperty.push(controlProperty);
}
ControlProperty.insertMany(arControlProperty, forceServerObjectId=true,function (err,data) {
if(err!=null){
return console.log(err);
}
console.log(" " + j + " controlProperties for control " + i + " saved");
control.controlProperties = data;
console.log(data);
});
}
arControls.push(control);
}
Control.insertMany(arControls, forceServerObjectId=true,function (err,data) {
if(err!=null){
return console.log(err);
}
survey.controls = data;
console.log("controls saved");
console.log(data);
});
}
survey
.save()
.then(result => {
console.log("survey saved");
res.status(201).json(survey);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
}
});
});
sample post data:
{
"name": "TestSurvey",
"description": "This is a test survey",
"controls": [
{
"controlType": "Label",
"name": "Label1",
"isInput": false,
"order": 1,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Large",
"order": 1
},
{
"propertyName": "BackgroundColor",
"propertyValue": "Darkgreen",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "Fill",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "TextColor",
"propertyValue": "White",
"order": 6
},
{
"propertyName": "Text",
"propertyValue": "Paris Work-Life Balance",
"order": 7
}
]
},
{
"controlType": "Label",
"name": "Label2",
"isInput": false,
"order": 2,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Medium",
"order": 1
},
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "Text",
"propertyValue": "Dear [[FirstName]], \nwas your workload on the case 12345 - 67(Company) compliant to the BCG Work Life Balance Ground Rules over the past week ?",
"order": 6
}
]
},
{
"controlType": "PWLBControl",
"name": "PWLB1",
"isInput": true,
"order": 3,
"controlProperties": [
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 1
}
]
},
{
"controlType": "Button",
"name": "button1",
"isInput": false,
"order": 4,
"controlProperties": [
{
"propertyName": "Text",
"propertyValue": "Submit",
"order": 1
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 2
},
{
"propertyName": "IsSubmitButton",
"propertyValue": true,
"order": 3
}
]
},
{
"controlType": "Image",
"name": "image1",
"isInput": false,
"order": 5,
"controlProperties": [
{
"propertyName": "Source",
"propertyValue": "",
"order": 1
},
{
"propertyName": "VerticalOptions",
"propertyValue": "End",
"order": 2
}
]
}
]
}
There is no need to keep seperate collections for controlProperties and controls.
You can embed controlPropertySchema inside controlSchema, and embed controlSchema inside surveySchema.
So at the end we will have only one collection for survey.
This will make possible to create a survey in one insert operation. And also you will be able to get all survey info in one read operation.
Also there are a few suggestions:
It is better to not add _id fields to the schemas, mongodb will
handle it.
I see you use it if a survey exists with the given _id. Better to
use name field to check if a survey already exists.
min and max options are used for Number type, for String type
minlength and maxlength are used. Docs
So the surveySchema must look like this:
const mongoose = require("mongoose");
const controlPropertySchema = new mongoose.Schema({
// _id: mongoose.Schema.Types.ObjectId,
// control: { type: mongoose.Schema.Types.ObjectId, ref: "Control" },
propertyName: {
type: String,
required: true
},
propertyValue: {
type: String,
required: true
},
order: {
type: Number,
required: true
}
});
const controlSchema = new mongoose.Schema({
//_id: mongoose.Schema.Types.ObjectId,
// survey: {type: mongoose.Schema.Types.ObjectId, ref: 'Survey'},
controlType: {
type: String,
required: true
},
name: {
type: String,
required: true
},
isInput: {
type: Boolean,
required: true
},
order: {
type: Number,
required: true
},
controlProperties: [controlPropertySchema]
//controlProperties: [{ type: mongoose.Schema.Types.ObjectId, ref: "ControlProperty" }]
});
const surveySchema = mongoose.Schema({
// _id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
minlength: 4,
maxlength: 255
},
description: {
type: String,
required: false,
maxlength: 1000
},
closeDate: {
type: Date,
required: false
},
controls: [controlSchema]
// controls: [{ type: mongoose.Schema.Types.ObjectId, ref: "Control" }]
});
module.exports = mongoose.model("Survey", surveySchema);
Now we can create a survey with this post route:
(Please note that we don't make any conversions, since our request body's structure is the same as surveySchema)
router.post("/surveys", async (req, res) => {
try {
let survey = await Survey.findOne({ name: req.body.name });
if (survey) {
return res.status(400).send("A survey already exists with that name");
}
const result = await Survey.create(req.body);
res.send(result);
} catch (err) {
console.log(err);
if (err.name === "ValidationError") {
return res.status(400).send(err.errors);
}
res.status(500).send("Something went wrong");
}
});
In your request body, there was an empty propertyValue so I changed it to "propertyValue": "I was empty",
and also a boolean value instead of string, so I changed it to "propertyValue": "I was true"
You can use this corrected request body:
{
"name": "TestSurvey",
"description": "This is a test survey",
"controls": [
{
"controlType": "Label",
"name": "Label1",
"isInput": false,
"order": 1,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Large",
"order": 1
},
{
"propertyName": "BackgroundColor",
"propertyValue": "Darkgreen",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "Fill",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "TextColor",
"propertyValue": "White",
"order": 6
},
{
"propertyName": "Text",
"propertyValue": "Paris Work-Life Balance",
"order": 7
}
]
},
{
"controlType": "Label",
"name": "Label2",
"isInput": false,
"order": 2,
"controlProperties": [
{
"propertyName": "FontSize",
"propertyValue": "Medium",
"order": 1
},
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 2
},
{
"propertyName": "FontAttributes",
"propertyValue": "Bold",
"order": 3
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 4
},
{
"propertyName": "HorizontalTextAlignment",
"propertyValue": "Center",
"order": 5
},
{
"propertyName": "Text",
"propertyValue": "Dear [[FirstName]], \nwas your workload on the case 12345 - 67(Company) compliant to the BCG Work Life Balance Ground Rules over the past week ?",
"order": 6
}
]
},
{
"controlType": "PWLBControl",
"name": "PWLB1",
"isInput": true,
"order": 3,
"controlProperties": [
{
"propertyName": "Margin",
"propertyValue": "20,0,20,0",
"order": 1
}
]
},
{
"controlType": "Button",
"name": "button1",
"isInput": false,
"order": 4,
"controlProperties": [
{
"propertyName": "Text",
"propertyValue": "Submit",
"order": 1
},
{
"propertyName": "HorizontalOptions",
"propertyValue": "StartAndExpand",
"order": 2
},
{
"propertyName": "IsSubmitButton",
"propertyValue": "I was true",
"order": 3
}
]
},
{
"controlType": "Image",
"name": "image1",
"isInput": false,
"order": 5,
"controlProperties": [
{
"propertyName": "Source",
"propertyValue": "I was empty",
"order": 1
},
{
"propertyName": "VerticalOptions",
"propertyValue": "End",
"order": 2
}
]
}
]
}
Thanks for all the valuable input.
Finally I found the reason why my code did not work from the beginning. Only thing I needed to change was to do the assignment of controlProperties array to control and the controls array to survey not in the success function of the insertMany but after the whole inserMany command.
So I changed:
ControlProperty.insertMany(arControlProperty, forceServerObjectId=true,function (err,data) {
if(err!=null){
return console.log(err);
}
console.log(" " + j + " controlProperties for control " + i + " saved");
control.controlProperties = data;
console.log(data);
});
to:
ControlProperty.insertMany(arControlProperty, forceServerObjectId=true,function (err,data) {
if(err!=null){
return console.log(err);
}
console.log(" " + j + " controlProperties for control " + i + " saved");
console.log(data);
});
control.controlProperties = arControlProperty;
Thanks for you support.
I am getting this output :
"Area":
[{
"AreaId": 2,
"AreaName":xyz,
"Data":
[{
"AssetId":somevalue,
"ActionId":somevalue,
}]
},
{
"AreaId": 2,
"AreaName":xyz,
"Data":
[{
"AssetId":somevalue,
"ActionId":somevalue,
}]
}]
But I want it merging to be like this :
"Area":[{
"AreaId": 2,
"AreaName":xyz,
"Data":
[{
"AssetId":somevalue,
"ActionId":somevalue,
},
{
"AssetId":someothervalue,
"ActionId":someothervalue,
}]
You could use groupBy of loadash. Code will look something like this
const {groupBy} = require("lodash");
const input = [
{
AreaId: 2,
AreaName: "Bedroom",
Data: [
{
Id: 7,
AssetId: 1,
Asset: "TubeLight",
ActionId: 1,
Action: "Clean",
TenantChargeBack: 0,
TenantChargeType: "%",
TenantChargeValue: 25,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 2,
AreaName: "Bedroom",
Data: [
{
Id: 8,
AssetId: 1,
Asset: "Bed",
ActionId: 3,
Action: "Repair",
TenantChargeBack: 1,
TenantChargeType: "%",
TenantChargeValue: 50,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 3,
AreaName: "Bathroom",
Data: [
{
Id: 9,
AssetId: null,
Asset: null,
ActionId: 2,
Action: "Replace",
TenantChargeBack: 1,
TenantChargeType: "$",
TenantChargeValue: 100,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 3,
AreaName: "Bathroom",
Data: [
{
Id: 10,
AssetId: 6,
Asset: "Jaar",
ActionId: 3,
Action: "Repair",
TenantChargeBack: 1,
TenantChargeType: "$",
TenantChargeValue: 100,
Notes: "",
FilePath: "AWS_Bucket_Name/filename.jpg"
}
]
},
{
AreaId: 2,
AreaName: "Bedroom",
Data: [
{
Id: 11,
AssetId: null,
Asset: null,
ActionId: 1,
Action: "Clean",
TenantChargeBack: 1,
TenantChargeType: "$",
TenantChargeValue: 50,
Notes: "",
FilePath: null
}
]
}
];
const groupedData = groupBy(input, i => i.AreaId);
const result = Object.keys(groupedData).map(j => {
const combined = groupedData[j];
return combined.reduce((a, b) => {
return {
"AreaId": a.AreaId,
"AreaName": a.AreaName,
"Data": a.Data.concat(b.Data)
};
})
});
console.log(JSON.stringify(result));
I have 2 mongoose Models/Schemas (Products & Merchants). When doing a .find() on Products it is returning all products, as expected but when doing it for Merchants it is returning everything (both merchant and product data) when it should just be returning merchants based off the defined schema. I have one collection on my mongoDB server which contains all my merchants and the products.
Any idea what I am missing?
Thanks
Merchants Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MerchantShema = new Schema({
merchants: [{
merchant_id: Number,
price_current: Number,
price_rrp: Number,
aff_link: String,
merchant_product_id: Number,
aw_image_url: String,
cost_scoop: String,
created_at: Date,
updated_at: Date
}]
});
module.exports = mongoose.model('Merchants', MerchantShema, 'products');
Products Model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProductSchema = new Schema({
ean: Number,
aw_product_id: Number,
product_name: String,
product_brand: String,
product_description: String,
img_sml: String,
img_lrg: String,
cat: String,
sub_cat: String,
weight: String,
rating: String,
created_at: Date,
updated_at: Date,
merchants: [{
merchant_id: Number,
price_current: Number,
price_rrp: Number,
aff_link: String,
merchant_product_id: Number,
aw_image_url: String,
cost_scoop: String,
created_at: Date,
updated_at: Date
}],
nutrition: [{
calories: Number,
protein: Number,
fat: Number,
sat_fat: Number,
carbs: Number,
sugar: Number,
salt: Number,
calories: Number
}],
ingredients: String,
flavours: String,
is_active: Boolean
});
module.exports = mongoose.model('Products', ProductSchema, 'products');
My Routes
app.get('/api/products', function(req, res) {
Products.find(function(err, products){
if (err) return console.error(err);
return res.send(products);
})
.where('is_active').equals('true')
});
app.get('/api/merchants', function(req, res){
Merchants.find(function(err, merchants){
if (err) return console.error(err);
return res.send(merchants);
});
});
Example of my collection
[
{
"_id": "55840f86e4b0ba19c15ee26d",
"merchant_id": "1111",
"merchant_aw_id": "1",
"merchant_name": "test merchant",
"merchant_url": "google.com",
"merchant_image": "",
"created_at": "",
"updated_at": "",
"merchants": []
},
{
"_id": "558426f9e4b0ba19c15ee495",
"ean": "123456789",
"aw_product_id": "55555",
"product_name": "Test Product",
"product_brand": "Test Brand",
"product_description": "This is a description for the test product",
"img_sml": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"img_lrg": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"cat": "Protein",
"sub_cat": "Protein",
"weight": "2.5kg",
"rating": "5",
"created_at": "",
"updated_at": "",
"nutrition": [
{
"salt": "1",
"sugar": "1",
"carbs": "1",
"sat_fat": "1",
"fat": "1",
"protein": "1",
"calories": "1"
}
],
"ingredients": "",
"flavours": "",
"is_active": "true",
"merchants": [
{
"merchant_id": 1111,
"price_current": 9.99,
"price_rrp": 15.99,
"aff_link": "google.com",
"merchant_product_id": 999,
"aw_image_url": "",
"cost_scoop": "43p",
"created_at": "",
"updated_at": ""
}
]
},
{
"ean": "123456789",
"aw_product_id": "55555",
"product_name": "Test Product",
"product_brand": "Test Brand",
"product_description": "This is a description for the test product",
"img_sml": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"img_lrg": "http://images.productserve.com/preview/6/3196/73/20/704322073.jpg",
"cat": "Protein",
"sub_cat": "Protein",
"weight": "2.5kg",
"created_at": "",
"updated_at": "",
"nutrition": [
{
"salt": "1",
"sugar": "1",
"carbs": "1",
"sat_fat": "1",
"fat": "1",
"protein": "1",
"calories": "1"
}
],
"ingredients": "",
"flavours": "",
"is_active": "true",
"merchants": [
{
"merchant_id": 1111,
"price_current": 9.99,
"price_rrp": 15.99,
"aff_link": "google.com",
"merchant_product_id": 999,
"aw_image_url": "",
"cost_scoop": "43p",
"rating": "5",
"created_at": "",
"updated_at": ""
}
]
}
]
In looking at your merchants model definition. You are calling products in your export:
module.exports = mongoose.model('Merchants', MerchantShema, 'products');
This should probably read
module.exports = mongoose.model('Merchants', MerchantShema, 'merchants');
Another thing I noticed is that you have two keys called "calories".
I ran the code and it now brings back merchants correctly. However, when you call products, it brings back the merchant as part of that schema, since merchants are included in products. Another way you can do this is to use a nested schema. You can read about those in this other thread: Mongoose subdocuments vs nested schema
Hope that helps.