MEAN & Geospatial queries - Find LineStrings Intersecting on Another One given Its Name - angularjs

I'm trying to build an application using MEAN but now I'm stuck when trying to find linestrings intersecting on another one given its name.
For instance, given the following image, poly1 and poly2 should have intersections while poly3 does not.
Let's suppose poly1 has the following coordinates and the following JSON:
{
"_id" : ObjectId("57ab2107505ab11b1bd8422e"),
"name" : "poly1",
"updated_at" : ISODate("2016-08-10T12:41:43.789+0000"),
"created_at" : ISODate("2016-08-10T12:41:43.780+0000"),
"geo" : {
"coordinates" : [ [14.59, 24.847], [28.477, 15.961] ],
"type" : "LineString"
},
"__v" : NumberInt(0)
}
When I run the query on MongoChef I find both poly1 and poly2 and I do not find poly3 like I want:
{
geo :{
$geoIntersects:{
$geometry :{
type: "LineString" ,
coordinates: [ [14.59, 24.847], [28.477, 15.961] ]
}
}
}
}
While, when I run the query on Mongoose given a Polyline Id/name it does not work
//Given
var linestringById = Linestrings.find({name : lineName});
var linestrings = Linestrings.find({});
//Works
query = linestrings.where({ geo : { $geoIntersects :
{ $geometry :
{ type : 'LineString',
coordinates : [ [27.528, 25.006], [14.063, 15.591] ]
}
} } });
//Does not work
query = linestrings.where({ geo : { $geoIntersects :
{ $geometry :
{ type : 'LineString',
coordinates : linestringById.geo.coordinates
}
} } });
//Also does not work:
query = linestrings.where({ geo : { $geoIntersects :
{ $geometry :
{ type : 'LineString',
coordinates : linestringById
}
} } });
This is the Schema for LineStrings:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// Creates a LineString Schema.
var linestrings = new Schema({
name: {type: String, required : true},
geo : {
type : {type: String, default: "LineString"},
coordinates : Array
},
created_at: {type: Date, default: Date.now},
updated_at: {type: Date, default: Date.now}
});
// Sets the created_at parameter equal to the current time
linestrings.pre('save', function(next){
now = new Date();
this.updated_at = now;
if(!this.created_at) {
this.created_at = now
}
next();
});
linestrings.index({geo : '2dsphere'});
module.exports = mongoose.model('linestrings', linestrings);
This is how I call the query from the front-end QueryController.js
/** Looks for LineStrings intersecting a given linestring **/
vm.polyIntersect = function () {
//Taking name from a form
vm.queryBody = {
name : vm.formData.poly1
};
// Post the queryBody
$http.post('/find-poly-intersection', vm.queryBody)
.success(function(queryResults) {
console.log(queryResults);
})
.error(function(queryResults) {
console.log('Error: no results found '+queryResults));
});
};
This is my Route.js:
/** Requiring Factories **/
var LinestringFactory = require('./factories/linestring.factory.js');
module.exports = function(app) {
// Retrieves JSON records for all linestrings intersecting a given one
app.post('/find-poly-intersection', function(req, res) {
LinestringFactory.findIntersections(req).then( function (linestrings) {
return res.json(linestrings);
}, function (error) {
return res.json(error);
})
});
}
This is my LineString.factory.js:
var Linestrings = require('../models/linestring-model.js');
exports.findIntersections = findIntersections;
/** Finds Linestrings Intersections **/
function findIntersections(req) {
return new Promise( function (resolve, reject) {
var lineName = req.body.name;
var linestringById = Linestrings.find({name : lineName});
var linestrings = Linestrings.find({});
//Check if that certain linestring exists with Lodash
if (_.isEmpty(linestringById) || _.isUndefined(linestringById)
|| _.isNull(linestringById)){
return reject('No Linestrings found for that Name');
} else {
query = linestrings.where({ geo :
{ $geoIntersects : { $geometry :
{ type : 'LineString',
coordinates : linestringById.geo.coordinates}
} } });
query.exec(function (err, intersections) {
if (err){
return reject(err);
}
return resolve(intersections);
});
}, function (error) {
return reject(error);
})
}
console.log in QueryController gives me always Object {} for any
linestring name.
This is the Mongoose Log of the query.
I'm making sure of inserting [lng, lat] coordinates
Have you any idea on why I can't find any LineString intersecting by Id while I can find them using straight coordinates?
Thanks in advance.

You are passing linestring.geo.coordinates in latitute,longitute format to the final query.
Mongodb accepts coordinates in the x,y format, hence it has to be longitude,latitude
Updated:
You will need to directly pass the linestring as $geometry.
query = linestrings.where({ geo : { $geoIntersects :
{
$geometry : lineStringbyId.
} } });

I finally managed to solve this issue with the following code
/** Finds Linestrings Intersections **/
function findIntersections(req) {
return new Promise( function (resolve, reject) {
var lineName = req.body.name;
Linestrings.findOne({name : lineName}).then( function (linestringById, error) {
if(error){
return reject({error : 'LineString not Found'});
}
queryIntersections(linestringById).then( function (response) {
return resolve(response);
});
});
}, function (error) {
return reject({error : 'Error while executing promise'});
});
}
function queryIntersections(linestringById) {
return new Promise( function (resolve, reject) {
if (_.isEmpty(linestringById) || _.isUndefined(linestringById) || _.isNull(linestringById)){
return reject({ error : 'No Linestrings found for that Name'});
} else {
query = Linestrings.where( { geo : { $geoIntersects : { $geometry : { type: 'LineString', coordinates: linestringById.geo.coordinates } } } } );
queryExec(query).then( function (intersections) {
return resolve(intersections);
});
}
}, function (error){
return reject({error : 'Error while executing promise'});
});
}
The error was caused by the fact that I did not pass correctly linestrings and linestringById objects to the query.
I hope it will help someone.

Related

In NodeJS, convert database query output to Json format

This is my code:
oracledb.getConnection(
{
user : "user",
password : "password",
connectString : "gtmachine:1521/sde1"
},
function(err, connection)
{
if (err) { console.error(err); return; }
connection.execute(
"SELECT filetype, filetypeid from filetype where filetypeid < 6",
function(err, result)
{
if (err) { console.error(err); return; }
response = result.rows;
console.log(response);
res.end(JSON.stringify(response));
});
This is the output
[["Ascii Text",1],["Binary",2],["Graphics - GIF",3],["Graphics - JPEG",4],["HTML",5]]
But my front end angularjs is expecting something in this format:
[{"filetype":"Ascii Text","filetypeid":1},{"filetype":"Binary","filetypeid":2}]
Does any one know what is the standard way to convert this?
These will convert your array of arrays into an array of objects:
var results = [["Ascii Text",1],["Binary",2],["Graphics - GIF",3],["Graphics - JPEG",4],["HTML",5]];
results = results.map(
function(item) {
return {
filetype: item[0],
filetypeid: item[1]
}
}
);
console.log(results);
And in ES6:
var results = [["Ascii Text",1],["Binary",2],["Graphics - GIF",3],["Graphics - JPEG",4],["HTML",5]];
results = results.map(item => ({filetype: item[0], filetypeid: item[1]}));
console.log(results);

update all values in the sub array of one object in mongodb using mongoose

user = {
'userid':'111',
'mail':[{
'time':22222,
'info':'this is a info1',
'read':false,
},{
'time':33333,
'info':'this is a info2',
'read':false,
}]
}
then, I want to change one user's read flag to true, how can i do for it ?
here is my answer:
User.update({
'userid':userid,
'mails':{
'$elemMatch':{
'read':false
}
}
},{
'$set':{
'mail.$.read':false,
'newmail':0,
}
}, { multi: true }, function (err, data) {
if(err > 0){
console.log('ReadMail err', err);
}
});
here is a simple example: my model is User !! my url is the path to the DB
var newUser = new User();
newUser.name = request.body.name;
newUser.email = request.body.email;
newUser.pass = request.body.pass;
newUser.position = request.body.pos;
newUser.phone = request.body.phone;
mongoose.connection.openUri(url);
var myquery = { _id : request.params._id };
console.log("updating...")
User.findByIdAndUpdate(myquery,{$set: newUser},{new: true},function(err, result) {
if(err)
{
throw err;
}
response.json({code: 0 , result});
});

angular chaining arrays of promises

I am building a website over a database of music tracks. The database is as follows :
music table contains musicid and title
musicrights table contains musicid and memberid
members table contains memberid and memberinfo.
I'm trying to build an array of objects in my database service, which each entry represents a track containing its rightholders (contains information aubout one rightholder but not his name) and their member info (contains name etc). The backend is sailsjs and the code is as follows :
angular.module("myapp").service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberid: rightHolder.memberid
})).then(function (res) {
rightHolder.member = res.data[0];
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/musicrights?where=" + JSON.stringify({
musicid: doc.musicid
})).then(function(res) {
// array of promises :
// each rightholder of a document has to solve member info
var rightHolders = [];
for (var i in res.data) {
var rightHolder = {
member: res.data[i].memberid,
type: res.data[i].membertype,
rights: res.data[i].memberrights
};
rightHolders.push(getHolderMember(rightHolder));
}
return ($q.all(rightHolders));
}).then(function(rightHolders) {
// expected array of one or two rightholders,
// enriched with member information
// actually returns array of one or two arrays of 30 members
// without rightholder info
console.log(rightHolders);
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
// array of 30 promises :
// each one of 30 documents has to resolve its rightholders
var documents = [];
for (var i in res.data) {
documents.push(getRightHolders(res.data[i]));
}
return ($q.all(documents));
}));
}
return (database);
}]);
The first array of promises seems to work as expected, but not the second one in getRightHolders. What is strange is that this function returns an array of one or two promises, which are rightHolders waiting for their memberinfo. But in the callback where I console.log the response, i get an array of one or two (as per the number of pushed promises) but this array's elements are arrays of 30 memberinfo instead of one memberinfo. I don't understand how this $q.all() call gets mixed with the previous-level $q.all.
The data structure is roughly like this
documents [ ] ($http => 30 responses)
music.musicid
music.rightHolders [ ] ($http => 1, 2, 3 responses)
rightholder.rights
rightholder.member ($http => 1 response)
member.memberinfo
Any help appreciated. Thank you !
UPDATE : Thank you for your answer, it worked like a charm. Here's the updated code, with also the migrate service which formats data differently (there is some database migration going on). I kept it out of the first example but your answer gave me this neat syntax.
angular.module("myApp").service("database", ["$q", "$http", "migrate", function($q, $http, migrate) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberID: rightHolder.member
})).then(function(res) {
return (migrate.member(res.data[0]));
}).then(function(member) {
rightHolder.member = member;
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/rightHolders?where=" + JSON.stringify({
musicID: doc.musicID
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.rightHolder)
.map(getHolderMember)
)
);
}).then(function(rightHolders) {
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
},
{
subtitle: {
contains: q
}
}
]
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.music)
.map(getRightHolders)
)
);
}));
}
return (database);
}
I'm not quite sure how you're getting the result you describe, but your logic is more convoluted than it needs to be and I think this might be leading to the issues you're seeing. You're giving the getRightsHolders function the responsibility of returning the document and based on your comment above, it sounds like you previously had the getHolderMember() function doing something similar and then stopped doing that.
We can clean this up by having each function be responsible for the entities it's handling and by using .map() instead of for (please don't use for..in with arrays).
Please give this a try:
angular
.module("myapp")
.service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(memberId) {
var query = JSON.stringify({ memberid: memberid });
return $http.get("/api/members?where=" + query)
.then(function (res) {
return res.data[0];
});
}
function populateRightsHolderWithMember(rightsHolder) {
return getHolderMember(rightsHolder.memberid)
.then(function (member) {
rightsHolder.member = member;
return rightsHolder;
});
}
function getRightHolders(doc) {
var query = JSON.stringify({ musicid: doc.musicid });
return $http.get("/api/musicrights?where=" + query)
.then(function(res) {
return $q.all(res.data.map(populateRightsHolderWithMember));
});
}
function populateDocumentWithRightsHolders(document) {
return getRightsHolders(document)
.then(function(rightsHolders) {
document.rightsHolders = rightsHolders;
return document;
});
}
database.music = function(q) {
return $http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
return $q.all(res.data.map(populateDocumentWithRightsHolders));
});
}
return (database);
}]);

Can't compare MongoDB data with javascript array

I want to compare the data which I got from Mongo to javascript array. I am using lodash to compare. But it always return incorrect result.
var editUser = function(userData, getOutFunction) {
var status = CONSTANTS.NG;
checkExistUser(userData._id).then(function(user) {
if (user !== null) {
var userGroup = JSON.stringify(user.group);
user.group = user.group.map((groupId) => {
return groupId.toString();
});
var removedGroups = _.difference(userGroup, userData.group);
var addedGroups = _.difference(userData.group, userGroup);
console.log('Removed Groups: ', removedGroups);
console.log('Added Groups: ', addedGroups);
} else {
status = CONSTANTS.NG;
logger.debug(DEBUG_CLASS_NAME, "Cannot find object");
if (typeof(getOutFunction) !== 'undefined') {
getOutFunction(status, null);
} else {
NO_CALLBACK();
}
}
}).catch(function() {
console.log('Promise is error');
});
var checkExistUser = function(userId) {
return new Promise(function(resolve, reject) {
UserDAO.findById(userId, function(err, user) {
if (err) {
logger.debug(DEBUG_CLASS_NAME, {
name: err.name,
code: err.code,
message: err.message,
method: "checkExist"
});
resolve(null);
} else {
resolve(user);
}
});
});
}
For example:When I try to input value for lodash difference function
var user.group = ["58b8da67d585113517fed34e","58b8da6ed585113517fed34f"];
var userData.group = [ '58b8da67d585113517fed34e' ];
I want lodash difference return below result:
Removed Groups: ['58b8da6ed585113517fed34f']
Added Groups: []
However, the function gave me the result like:
Removed Groups: []
Added Groups: [ '58b8da67d585113517fed34e' ]
Can anyone help me in this case?
I will do appreciate it.
I have had this issue as well, the result from mongodb is an ObjectId type so you can compare the someObjectId.toString() value with your array of strings, or you could use
someObjectId.equals(stringOrObjectIdValue)
However, if you want to keep using lodash functions you will either have to force both arrays to strings or to ObjectIds before passing them into the function.

Angular Resource PUT Operation with Payload

I have the following factory to send query to server:
app.factory('Request', ['$resource',
function ($resource) {
var res = $resource("bin/server.fcgi/REST/" + ':resourceName/:ID', {}, {
get : {
method : 'GET'
},
put : {
method : "PUT"
}
});
return {
get : function (arguments, b, c) {
return res.get(arguments, b, c).$promise;
},
put : function(arguments,b,c){
return res.put(arguments, b, c).$promise;
}
};
}
]);
I call it like this:
Request[methodName](params).then(successFunction).catch (failFunction);
However, if i want to send a PUT query:
Request["put"](params).then(successFunction).catch (failFunction);
where
params = {
resourceName : "ATable",
ID : 222,
AProperty : "changedValue"
}
I take then following request: (so an error)
http://myadres.com/REST/ATable/222?AProperty=changedValue
instead of
http://myadres.com/REST/ATable/222
with payload
{ AProperty:changedValue }
What is wrong with this?
app.service('Request', ['$resource',function ($resource) {
var res = $resource('bin/server.fcgi/REST/:resourceName/:ID',
{resourceName: "#resourceName", ID: "#ID"},
{
get : { method : 'GET'},
put : { method : "PUT", params: {resourceName:"#resourceName", ID: "#ID"}//you can leave the string empty if you dont want it to be a defualt value like ID:""
});
this.get = function () {
return res.get().$promise;
}
this.put = function(obj){
return res.put(obj).$promise; // it can be also {like json with your params}
}
]);
and then call it from controller by
var obj = {
ID:222,
resourceName:'ATable'
}
Request.put(obj).then(function(data){
//check whats the data
})
this is how it should be done
maybe not the best way but should work

Resources