OData read inside a read success handler not working [duplicate] - sapui5

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I'm new to SAPUI5 and I'm having problems...
When I use a read function to get a value from an OData service, I'm trying to use another read function inside the success function, using a filter with the value that I obtained from the first read.
Is this even possible?
Up to now, it just seems like it reads successfully, but then it doesn't execute the next read.
var filters = new Array();
var first_Filter = new sap.ui.model.Filter({
path: "userId",
operator: sap.ui.model.FilterOperator.EQ,
value1: userId
});
filters.push(first_Filter);
this.getOwnerComponent().getModel().read("/users", {
filters: la_filters,
success: function(oData, response) {
var data = oData.results[0];
var jobid = data.jobId;
var filters2 = new Array();
var second_Filter2 = new sap.ui.model.Filter({
path: "idJob",
operator: sap.ui.model.FilterOperator.EQ,
value1: jobid
});
filters2.push(second_Filter2);
this.getOwnerComponent().getModel().read("/jobs", {
filters: la_filters2,
success: function(oData2) {
// read odata ,get value and pass it on...
}
});
}
});

the this inside the second read is not the correct one.
save a reference to this (outside the first read) like var that = this; and use it to make the second read like
that.getOwnerComponent().getModel().read("/jobs", {
filters: la_filters2,
success: function(oData2) {
// read odata ,get value and pass it on...
}
});

Related

How to update a nested model in mongoose and mongodb

I'm building a MEAN stack web application.
I have a model in mongoose like this. A model name analyses, where inside , there is a property call points which is another small model name analysis
//model file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var analysis = new Schema({
ref_id: String,
ele_name: String,
pos_x: Number,
pos_y: Number,
pos_pix_x: Number,
pos_pix_y: Number,
});
var analyses = new Schema({
img_id: String,
store_file_name:String,
points: {
type: [analysis],
default: undefined
},
});
module.exports = mongoose.model('analyses', analyses);
In the database , after I create an entry. there something like this
As you can see, there an id of analyses (5bb...820e) inside have an array of points ( analysis), each has their own id ( 5bb...26d)
Now if I want to update this. I use ExpressJS to define the update API of the server
// API define file
var express = require('express');
var analysesRoutes = express.Router();
// Require Item model in our routes module
var Analyses = require('../models/analyses');
// Defined update route
analysesRoutes.route('/update/:id').put(function (req, res) {
Analyses.findById(req.params.id, function(err, analyses) {
if (!analyses)
return next(new Error('Could not load Document'));
else {
for ( item of Object.keys(req.body)){
analyses[item] = req.body[item];
}
analyses.save().then(analyses => {
res.json({...analyses, status: 200});
})
.catch(err => {
res.status(400).send("unable to update the database");
});
}
});
});
But my problem here is if I want to update only 1 analysis point, I have to send the request to update the big analyses object ( call out id 5bb...820e). Something like this :
//service file
updateAnalyses(newObj, id) {
const uri = 'http://localhost:4000/analyses/update/' + id;
this
.http
.put(uri, newObj)
.subscribe(res => console.log('Done'));
}
// Where newObj here is a big analyses object contains all the unnecessary detail + the point need to be updated
In fact, that point also have an id ( 5bb..26d) itself, is there anyway to update directly to that analysis point ??
Similar question was answered before in Stack overflow.
You can refer to it from here: MongoDB update data in nested field
P.S. There are many answers related to mongodb. Personally the parent.$.child notation worked for me.

How to alter a value before storing it to the database in Keystone JS

Keystone and mongo are both new to me, so I'm unsure how to manipulate data.
I have a Keystone list which has a model (/models/Game.js) that looks like:
var keystone = require('keystone');
var Types = keystone.Field.Types;
var Game = new keystone.List('Game');
Game.add({
odds: { type: Types.Text, required: true, initial: true},
});
Game.track = true;
Game.defaultSort = '-createdAt';
Game.defaultColumns = 'odds';
Game.register();
The odds field is a string, e.g. 3/1, and I want to run this through a function that splits it and returns a decimal version, for example:
function decimalOdds(fraction) {
const splitFields = fraction.split('/');
return ((splitFields[0] / splitFields[1]) + 1).toFixed(2);
}
It's the return value of that function that I want to be stored as the 'odds' in the data base. Is that possible?
You can use a pre save hook:
Game.schema.pre('save', function(next) {
if (this.isModified('odds')) {
this.odds = decimalOdds(this.odds)
}
next()
})
You can read more in the schema plugins section of the docs:
http://keystonejs.com/docs/database/#lists-plugins
You can also find more information on Mongoose schema hooks here:
http://mongoosejs.com/docs/middleware.html

"Cannot Read property sPath of undefined" when calling .read with filters [duplicate]

This question already has answers here:
Why my filter is not working in v2.ODataModel "read"?
(3 answers)
Closed 18 days ago.
I want to execute an OData Get request with filter from SAPUI5. The OData URL would look as follows:
/sap/opu/odata/MAT_SRV/Get_MATSet?$filter=(Plant eq 'A1HG') and (MaterialType eq 'PS01') and ((MaterialNumber eq '61345280') or (MaterialNumber eq '61345280'))
Here, I have created the filter array for the OData service (oDataFilter in the example below) as follows:
var oPlant = new Filter("Plant", FilterOperator.EQ, "A1HG");
var oPlantFilter = new Filter({
filters: [oPlant],
and: true
});
var oMatType = new Filter("MaterialType", FilterOperator.EQ, "PS01");
var oMatTypeFilter = new Filter({
filters: [oMatType],
and: true
});
var oMaterialNumberFilter = this._getMatNumbers(); //GET ALL MATERIAL NUMBER FILTERS SEPERATED By OR
var oDataFilter = new Filter({
filters: [
oPlantFilter,
oMatTypeFilter,
oMaterialNumberFilter
],
and: true
});
BackEndModel.read("/Get_MATSet", {
filters: oDataFilter,
success: jQuery.proxy(this.fSuccess, this),
error: jQuery.proxy(this.fError, this)
});
_getMatNumbers: function() {
var aTokens = this.byId("Mat_MultiInput").getTokens(); //ITERATE THROUGH EACH VALUES ENTERED BY USER
var aMatFilter = [];
for (var i in aTokens) {
aMatFilter.push(new Filter("MaterialNumber", FilterOperator.EQ, aTokens[i].getKey()));
}
var oFilter = new Filter({ filters: aMatFilter, and: false });
return oFilter;
}
However, I got the following error while execution:
Cannot Read property sPath of undefined.
Can someone please tell me what I am doing wrong here? Or guide with the filter expression to be passed to the OData service which corresponds to the filter values mentioned in the OData URL?
I looked up one of my codings with filters and found "my" oDataFilter to be an array. So try this:
var oDataFilter = [
new Filter({
filters: [
oPlantFilter,
oMatTypeFilter,
oMaterialNumberFilter
],
and: true
})
];
Since in your oPlantFilter and oMatTypeFilter contains only one filter criteria ypu can directly use them inside the oDataFilter as shown below. I hope it will help you to solve the problem. And one more thing concentrate on the path or property name with their data type.
var oPlantFilter = new sap.ui.model.Filter("Plant", sap.ui.model.FilterOperator.EQ, 'A1HG');
var oMatTypeFilter = new sap.ui.model.Filter("MaterialType", sap.ui.model.FilterOperator.EQ, 'PS01');
var oMaterialNumberFilter = this._getMatNumbers();
var oDataFilter = new sap.ui.model.Filter({
filters: [oPlantFilter, oMatTypeFilter, oMaterialNumberFilter],
and: true
});
BackEndModel.read( "/Get_MATSet", {
filters: oDataFilter,
success: jQuery.proxy(this.fSuccess, this),
error: jQuery.proxy(this.fError, this)
});
_getMatNumbers: function() {
var aTokens = this.byId("Mat_MultiInput").getTokens();
var aMatFilter = [];
for (var i in aTokens) {
aMatFilter.push(new sap.ui.model.Filter("MaterialNumber", sap.ui.model.FilterOperator.EQ, aTokens[i].getKey()));
}
var oFilter = new sap.ui.model.Filter({
filters: aMatFilter,
and: false
});
return oFilter;
}

Handling nested callbacks/promises with Mongoose

I am a beginner with Node.js and Mongoose. I spent an entire day trying to resolve an issue by scouring through SO, but I just could not find the right solution. Basically, I am using the retrieved values from one collection to query another. In order to do this, I am iterating through a loop of the previously retrieved results.
With the iteration, I am able to populate the results that I need. Unfortunately, the area where I am having an issue is that the response is being sent back before the required information is gathered in the array. I understand that this can be handled by callbacks/promises. I tried numerous ways, but I just haven't been successful with my attempts. I am now trying to make use of the Q library to facilitate the callbacks. I'd really appreciate some insight. Here's a snippet of the portion where I'm currently stuck:
var length = Object.keys(purchasesArray).length;
var jsonArray = [];
var getProductDetails = function () {
var deferred = Q.defer();
for (var i = 0; i < length; i++) {
var property = Object.keys(purchasesArray)[i];
if (purchasesArray.hasOwnProperty(property)) {
var productID = property;
var productQuery = Product.find({asin:
productQuery.exec(function (err, productList) {
jsonArray.push({"productName": productList[0].productName,
"quantity": purchasesArray[productID]});
});
}
}
return deferred.promise;
};
getProductDetails().then(function sendResponse() {
console.log(jsonArray);
response = {
"message": "The action was successful",
"products": jsonArray
};
res.send(response);
return;
}).fail(function (err) {
console.log(err);
})
});
I am particularly able to send one of the two objects in the jsonArray array as the response is being sent after the first element.
Update
Thanks to Roamer-1888 's answer, I have been able to construct a valid JSON response without having to worry about the error of setting headers after sending a response.
Basically, in the getProductDetails() function, I am trying to retrieve product names from the Mongoose query while mapping the quantity for each of the items in purchasesArray. From the function, eventually, I would like to form the following response:
response = {
"message": "The action was successful",
"products": jsonArray
};
where, jsonArray would be in the following form from getProductDetails :
jsonArray.push({
"productName": products[index].productName,
"quantity": purchasesArray[productID]
});
On the assumption that purchasesArray is the result of an earlier query, it would appear that you are trying to :
query your database once per purchasesArray item,
form an array of objects, each containing data derived from the query AND the original purchasesArray item.
If so, and with few other guesses, then the following pattern should do the job :
var getProductDetails = function() {
// map purchasesArray to an array of promises
var promises = purchasesArray.map(function(item) {
return Product.findOne({
asin: item.productID // some property of the desired item
}).exec()
.then(function product {
// Here you can freely compose an object comprising data from :
// * the synchronously derived `item` (an element of 'purchasesArray`)
// * the asynchronously derived `product` (from database).
// `item` is still available thanks to "closure".
// For example :
return {
'productName': product.name,
'quantity': item.quantity,
'unitPrice': product.unitPrice
};
})
// Here, by catching, no individual error will cause the whole response to fail.
.then(null, (err) => null);
});
return Promise.all(promises); // return a promise that settles when all `promises` are fulfilled or any one of them fails.
};
getProductDetails().then(results => {
console.log(results); // `results` is an array of the objects composed in getProductDetails(), with properties 'productName', 'quantity' etc.
res.json({
'message': "The action was successful",
'products': results
});
}).catch(err => {
console.log(err);
res.sendStatus(500); // or similar
});
Your final code will differ in detail, particularly in the composition of the composed object. Don't rely on my guesses.

Why my filter is not working in v2.ODataModel "read"?

I am using the OData model to read data. But it doesn't work. Check the code below:
getGuid: function(pernr) {
var self = this;
var url = "/PersonalDetailSet?$filter=Pernr eq '00000001'";
self.setBusy(true);
this.oModel.read(url, {
success: function(res) {
// ...
},
error: function() {
// ...
}
});
}
I don't know why the filter in url is not working now?
Check if your OData service supports the $filter query in the first place.
Use the read method correctly:myV2ODataModel.read("/PersonalDetailSet"/* No $filter queries here! */, {
filters: [ // <-- Should be an array, not a Filter instance!
new Filter({ // required from "sap/ui/model/Filter"
path: "myField",
operator: FilterOperator.EQ, // required from "sap/ui/model/FilterOperator"
value1: "..."
})
],
// ...
});
API reference: sap.ui.model.odata.v2.ODataModel#read
API reference: sap.ui.model.Filter
First you check whether you are getting model in the scope or not. As i can see this.oModel which is not proper way of getting model. Better use this.getModel() or this.getView().getModel() and then check the call. Passing filter is not the right way but still it should work.
If you want to apply additional URL Parameters in the read function you have to do this via the "urlParameters" parameter:
getGuid: function(pernr){
var self = this;
var url = "/PersonalDetailSet";
self.setBusy(true);
this.oModel.read(url, {
urlParameters: {
"$filter" : "Pernr eq '00000001'"
},
success: function(res){
self.setBusy(false);
self.guid = res.results[0].Guid;
},
error: function() {
self.setBusy(false);
}
});
}