Good day,
I am sorry if my question could be basic but I think I do have a problem to convert a string to an array.
I am trying to add a polygon to a map (or to a layer). I extracted some polygon coordinates from a MYSQL database to show it into a map.
First here is my code:
function getGeofences(devise_id){
$.ajax({
type: "POST",
url: "maps/sql/getGeofences.php",
data: {devise_id:devise_id},
success: result,
error: error,
dataType: "json"
});
function error(data)
{
console.log("Error getGeofences");
console.log(data);
}
function result(data){
console.log("Geofences from DB");
for (var i = data.features.length - 1; i >= 0; i--) {
console.log(data.features[i].geometry.coordinates);
//var polygon = L.polygon(data.features[i].geometry.coordinates, {color: 'red'});
var polygon = L.polygon([[51.436888577205,-1.373291015625],[51.169011079452,-1.494140625],[51.158676864424,-0.8624267578125],[51.505323411493,-0.889892578125],[51.436888577205,-1.373291015625]] , {color: 'red'});
polygon.addTo(map);
}
}
}
This:
console.log(data.features[i].geometry.coordinates);
shows/prints that:
"[[51.436888577205,-1.373291015625],[51.169011079452,-1.494140625],[51.158676864424,-0.8624267578125],[51.505323411493,-0.889892578125],[51.436888577205,-1.373291015625]]"
I do not understand why this
var polygon = L.polygon([[51.436888577205,-1.373291015625],[51.169011079452,-1.494140625],[51.158676864424,-0.8624267578125],[51.505323411493,-0.889892578125],[51.436888577205,-1.373291015625]] , {color: 'red'});
works!
But this:
var polygon = L.polygon(data.features[i].geometry.coordinates, {color: 'red'});
does not work!
Keeping in mind, this:
data.features[i].geometry.coordinates
print that:
[[51.436888577205,-1.373291015625],[51.169011079452,-1.494140625],[51.158676864424,-0.8624267578125],[51.505323411493,-0.889892578125],[51.436888577205,-1.373291015625]]
I think, it is because the content of
data.features[i].geometry.coordinates
is, in fact, a string with several '[[]]'
Now, I do not know how to convert the above string to an rwally array. So, I do not know what is exactly true in my written, but I need to "parse" the content of
data.features[i].geometry.coordinates
and I do not know how!
Would you suggest me a solution?
Related
I have a schema through mongoose:
const mongoose = require('mongoose');
const recipeSchema = mongoose.Schema({
title: String,
chef: String,
updated: {type: Date, default: Date.now},
region: String,
ingredients: [String],
instructions: [String]
}, { collection: 'recipes' })
module.exports = mongoose.model('Recipes', recipeSchema);
I find the mongoose docs really difficult to understand. I am trying to search for a match of all substring within the 'ingredients' array. I read somewhere that it could be done like so:
.find({ingredients: 'ing1'}) // not working
.find({'ing1': {$in: ingredients}}) // not working
I find it pretty difficult to find in depth tutorials on mongoose as well. Im thinking about not using it at all anymore and just sticking to mongodb shell.
You can use a regex search to match substrings:
.find({ingredients: /ing1/})
The reason that you use mongoose is for testability.
Instead of having to work with a MongoDb instance, which, in Windows can be a pain with the .lock file and the service, mongoose creates the schema that you can test your code with.
The mongoose way is ideal for TDD/TFD.
Below is the model and the mocha test:
recipemodel.js
var mongoose = require('mongoose'),Schema=mongoose.Schema;
var RecipeSchema = new mongoose.Schema({});
RecipeSchema.statics.create = function (params, callback) {
'\\ params is any schema that you pass from the test below
var recipe = new RecipeSchema(params);
recipe.save(function(err, result) {
callback(err, result);
});
return recipe;
};
var recipemodel=mongoose.model('Model', RecipeSchema);
module.exports = recipemodel;
You don't need to describe the schema, mongoose will create it for you when you pass the values of the collection from a mocha test, for example!
The mocha test is below:
var mongooseMock = require('mongoose-mock'),
proxyquire = require('proxyquire'),
chai = require('chai'),
expect = chai.expect,
sinon = require('sinon'),
sinonChai = require("sinon-chai");
chai.use(sinonChai);
describe('Mocksaving a recipe ingredient', function () {
var Recipe;
beforeEach(function () {
Recipe = proxyquire('./recipemodel', {'mongoose': mongooseMock});
});
it('checks if ingredient '+'ing1' + ' saved to mongoose schema', function
(done) {
var callback = sinon.spy();
var recipe = Recipe.create({ title: "faasos", chef:
'faasos',region:'Chennai',ingredients:'ing1',instructions:'abc' },
callback);
expect(recipe.save).calledOnce;
expect(recipe.ingredients).equals('ing341');
done();
});
});
The call to a sinon spy is simply to ensure that the call to the data in the schema got saved (mock saved!) and that the 'save' method did get called at least once. This logic flow is in sync with your actual logic, as you would use in code, when the save on a mongodb collection would be made.
Simply change the value to 'ing1' to make the test pass when you run the test.
For an array type, pass the values as below:
var recipe = Recipe.create({ title: "faasos", chef:
'faasos',region:'Chennai',ingredients:'ing341,ing1',instructions:'abc' }, callback);
expect(recipe.save).calledOnce;
expect(recipe.ingredients).to.include('ing1');
Try this:
.ingredients.find((i) => i === "ing1")
for all elements in the ingredients array, it looks if the content, here a string element, is strictly equal to "ing1"
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.
Here is my helpers to diplay data from two collections
Template.Lirescategorie.helpers({
scategories: function () {
var cursor = Scategories.find();
var data = [];
cursor.forEach(function(somewhat) {
var categories = Categories.findOne({_id : somewhat.categorieID}, {categorie:1});
data.push({cat : categories.categorie, scat : somewhat.scategorie });
});
return data;
}
});
Here are my collections
categorie :
{
"_id": "LBKZQfZZSf4DRdeXo",
"categorie": "Citoyenneté"
}
scategorie
{
"_id": "cNHYpAEvC9ffjWkf5",
"categorieID": "LBKZQfZZSf4DRdeXo",
"scategorie": "Etat-Civil"
}
I'm pretty sure my helpers' code is not optimal. And i think by using _.map or something like that i can reduce the code.
Since i'm not really familiar to it, i'm looking for help about this.
Welcome to client-side joins. You can use .map() to get the list of categorieIDs and do the second find in one go with $in::
var cursor = Scategories.find();
var arrayOfCategorieIDs = cursor.map(function(s){return s.categorieId});
var categories = Categories.find({_id : {$in: arrayOfCategorieIDs}});
Then:
var sCategories = cursor.map(function(s){return s.scategorie}); // array of scategorie names
var categoryNames = categories.map(function(c){return s.categorie}); // array of categorie names
Then assemble these two arrays of strings into the array of objects you're looking for.
But there's a far simpler pattern for a client-side join: just iterate over one cursor and do the lookup into the related collection in a helper. For example:
html:
{{#each sCategories}}
{{sCategorie}}
{{categorie}}
{{/each}}
js:
Lirescategorie.helpers({
sCategories:(){
return Scategories.find();
},
categorie:(){
return Categories.findOne(this.categorieID).categorie;
}
});
I'm fiddling around with some scraping, and need to manipulate some of the data before writing it to my json file.
var Xray = require('x-ray');
var x = Xray();
x('http://myUrl.com', '#search_results div div a', [{
title: '.responsive_search_name_combined .search_name .title',
price: '.col.search_price.responsive_secondrow',
}])
.paginate('.search_pagination_right a.pagebtn:last-child#href')
.limit(10)
.write('data.json');
When saved, price looks like this: "price": "\r\n\t\t\t\t\t\t\t\t13,99€\t\t\t\t\t\t\t".
I guess its because theres a lot of spaces in div.col.search_price.responsive_secondrow.
<div class="col search_price responsive_secondrow">
9,99€ </div>
So my question is: Would it be possible to manipulate the data before .write?
Yes, you can simply provide a callback function that takes an object which is the result of your scrape. In this function you can take full control of any post-processing you want to do.
So your code would end up something like:
x('http://myUrl.com', '#search_results div div a', [{
title: '.responsive_search_name_combined .search_name .title',
price: '.col.search_price.responsive_secondrow',
}])
(function(products){
var cleanedProducts = [];
products.forEach(function(product){
var cleanedProduct = {};
cleanedProduct.price = product.price.trim();
//etc
cleanedProducts.push(cleanedProduct)
});
//write out results.json 'manually'
fs.writeFile('results.json', JSON.stringify(cleanedProducts));
})
You could use X-Ray native supported approach which is called filter functions and completely covers the case you described.
filters are custom defined functions allowing you to implement custom logic while processing scraped data.
See code sample below. There's a custom defined filter function with name of cleanUpText and apply it to scraped data price.
var Xray = require('x-ray');
var x = Xray({
filters: {
cleanUpText: function (value) { return value.replace('\r\n\t\t\t\t\t\t\t\t', '').replace('\t\t\t\t\t\t\t', ''); },
}
});
x('http://store.steampowered.com/search/?filter=topsellers', '#search_results div div a', [{
title: '.responsive_search_name_combined .search_name .title ',
price: '.col.search_price.responsive_secondrow | cleanUpText', // calling filter function 'cleanUpText'
}])
.paginate('.search_pagination_right a.pagebtn:last-child#href')
.limit(10)
.write('data.json');
data.json looks like below:
{"title": "PLAYERUNKNOWN'S BATTLEGROUNDS",
"price": "$29.99"},
{"title": "PAYDAY 2: Ultimate Edition",
"price": "$44.98"}
I have using mongoose with NodeJS and have the following model:
var Post = new Schema({
...
location: [Number, Number],
...
});
Post.index({ location: '2d' });
Post.set('autoIndex', false);
module.exports = mongoose.model('Post', Post);
When a user makes a query for all posts, they can add an optional query param near to find posts with locations within a given radius of near
GET /api/1.0/posts?near=12.3244,-1.23244
To get this to work, I'm doing the following:
if(req.query.near) {
var loc = req.query.near.split(',');
var area = { center: loc, radius: 10, unique: true, spherical: true };
if(loc.length === 2) {
query
.where('location')
.within()
.circle(area);
}
}
And then I execute the query.
I did this using this mongoose documentation
I've got 3 questions:
What is the unit of radius, miles or kilometers?
Do I divide the radius by 3963.2 like it is done here (the equatorial radius of the earth), or does mongoose handle that?
What does unique mean? (up above) and spherical? I'm supposing spherical means to use mongo's $centerSphere as opposed to $center, is that right?
I'd appreciate any help, especially for questions 2 and 1
Thanks :)