Mongoose.Create is not sending assigned value - javascript

Update: (The answer below was correct and helped to change the code, the issue now lies with mongoose and mongoDB, where mongoose appears to attempt a writing creating the collection but not actually writing the documents)
Why can't I bind the item that is nested in the req.body.goe.coordinates.0 or .1 The req.body.geo.coordinates is showing as an object which has an array of two numbers (coordinates). So far I can get the server to write all the other fields accept the geo field.
I assumed i could use req.body.geo.coordinates.0 because zero would be the first number in the array, right? i must be thinking of the req.body incorrectly and trying to access it in a manner that isn't correct.
How can I access these coordinates so that I can place them in the correct spot in the mongoose schema. I tried loading it as a whole object but mongoose wouldn't write that geo portion and would use the default.
As always thank you for you responses.
relevant part of mongoose schema:
var itemsSchema = new Schema({item:{
user_name: {type: String, default: 'badboy for life'},
city: {type:String},
geo:{
gtype: {type:String, default: "Point"},
coordinates: {longitude: {type:Number, default: -97.740678},
latitude: {type:Number, default: 30.274026 }},
},
title: {type: String, match: /[a-z]/},
desc: {type:String},
cost:{type: Number, index: true},
//Still can't get the image to load into mongoose correctly I'm assuming
// i'm doing it wrong but that's a question for another day.
//image: {
// mime: {type:String},
// bin: Buffer,
// }
}});
Express app.post that handles the post to the mongoDB server. It currently spits out the default values.
app.post('/js/dish', parser, function(req, res) {
var a = req.body.user_name;
var b = req.body.title;
var c = req.body.cost;
var d = req.body.ingdts;
var e = req.body.location;
var f = req.body.geo.coordinates.0;
var g = req.body.geo.coordinates.1;
// create an object, information comes from AJAX request from Angular
console.log(req.body.geo["coordinates"]);
console.log("hey the object request has this in it: "+ req, req.method);
Item.create({"item.user_name":a, "item.title": b, "item.cost": c, "item.desc": d, "item.city": e, "item.geo.coordinates.latitude":f,"item.geo.coordinates.longitude":g},
function(err, item) {
if (err){
res.send(err);
}else{
// get and return all the items after you create another
getItems(res);
}
});
Map Service in Angular which gets and Sets GPS
(function(){
var mapSrvc = angular.module("mapService",[]);
console.log('map factory baby!')
var position = [];
var mapPopulation = [];
mapSrvc.service('Maping',['$http',function(){
return{
getUserGPS:function(){
return position;
},
setUserGPS:function(lat,long){
return position = [lat,long];
},
getMapPop:function(dbLocs){
return mapPopulation = dbLocs;
}
}
}])
})();
The Angular control which is setting the value and sending it to the express portion of the app
$scope.createItem = function(item){
if($scope.items.text != false){
var itemCord = Maping.getUserGPS();
$scope.items={
user_name: item.user_name,
title: item.title,
cost: item.cost,
location: item.location,
ingdts: item.ingdts,
geo:{coordinates:{longitude:itemCord[1],latitude:itemCord[0]}}
}
console.log("breadcrumb to see if item was defined: ",$scope.items)
$scope.loading = true;
Items.create($scope.items)
.success(function(data){
Items.get()
.success(function(data){
$scope.items= data;
$scope.loading = false;
console.log(data);
})
.error(function(err){
console.log('Error: ' + err);
});
$scope.loading=false;
$scope.items= {};
$scope.items= data;
})
.error(function(err){
console.log('Error: ' + err);
});
}
};

Your coordinates object in your schema is an object literal, not an array.
Array elements can be accessed by index, but not in the way you assumed. In an array, you'd access elements with bracket notation so consider the following:
var foo = ["bar", "baz"];
console.log(foo[0]);
For an object however, unless you're actually grabbing keys named 0 and 1, it doesn't work in the same way.
If you want to access longitude and latitude in the bracket notation above, the coordinates object in your Schema would have to be an array. Although, that kind of makes naming the values and putting them in the longitude and latitude objects kind of useless. Talking about this part here (I took out the comment to make it easier to follow):
coordinates: {longitude: {type:Number, default: -97.740678}, latitude: {type:Number, default: 30.274026 }},
You have another option which may be more suitable. Just access the values in the coordinates object by key. Do you know how object literals work in JavaScript? Instead of accessing values by number (or index) you access them by the names you gave them (or the keys). So you'd instead access the values like this:
var f = req.body.geo.coordinates.longitude;
var g = req.body.geo.coordinates.latitude;
... because that's what you named them.
To simply things, to access by index, either name the keys 0 and 1 instead of longitude and latitude in the coordinates object (you probably should not do this) or make the coordinates object into an array like in the above example with foo, or access the keys by the names that you gave them like that directly above.

Related

How do I set multiple values of a JSON object?

So I've been working on this project but I'm stuck because I can't figure out how I should go about setting the other values of this new JSON object. So basically on the front end I have this:
HTML page view. The 'cat4' ID is the new object I tried to create, and illustrates the error I'm trying to fix. The problem is that I'm having trouble setting the LIMIT value of newly created objects (or multiple values at all). Here is the code where the object is created:
function sendCat()
{
window.clearTimeout(timeoutID);
var newCat = document.getElementById("newCat").value
var lim = document.getElementById("limit").value
var data;
data = "cat=" + newCat + ", limit=" + lim;
var jData = JSON.stringify(data);
makeRec("POST", "/cats", 201, poller, data);
document.getElementById("newCat").value = "Name";
document.getElementById("limit").value = "0";
}
In particular I've been playing around with the line data = "cat=" + newCat + ", limit=" + lim; but no combination of things I try has worked so far. Is there a way I can modify this line so that when the data is sent it will work? I find it odd that the line of code works but only for setting one part of the object.
The JSON.stringify() method converts a JavaScript object or value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.
MDN
I think this is what you want:
const newCat = 'Meow';
const newLimit = 5;
const data = {
cat: newCat,
limit: newLimit
}
console.log(JSON.stringify(data));
What you're referring to as a 'JSON object' is actually just a javascript object, you can make one using object literal syntax. An object literal with multiple properties looks like this:
var data = {
cat: newCat,
limit: lim
};
makeRec("POST", "/cats", 201, poller, JSON.stringify(data));
assuming the fifth parameter to makeRec is supposed to be the POST request body as stringified JSON, as your code seems to imply

javascript - JSON file use a value only if key exists

I'm retrieving an OSM Json from an overpass call, to obtain a list of features that I have to save on a database. Since the data are very different from one another (for example, some of them do have a a tag called "addr:city", and some of them not), I would like to check if a key exists, and only in that case save the corresponding value. I've found only this question but it's not my case, since I do not know a priori which keys one element will have and which not, and since I'm working with a great load of data, I really can't check the elements one by one and of course I can't write an IF for each case.
Is there a way to solve this? I was thinking something about "if key has null value, ignore it", while looping over the elements, but I don't know if something like that exists
EDIT:
This is my query:
https://overpass-api.de/api/interpreter?data=[out:json][timeout:25];(node[~%22^(tourism|historic)$%22~%22.%22](44.12419,%2012.21259,%2044.15727,%2012.27696);way[~%22^(tourism|historic)$%22~%22.%22](44.12419,%2012.21259,%2044.15727,%2012.27696););out%20center;
and this is the code I'm using to save the data on firebase:
results.elements.forEach(e=>{
var ref = firebase.database().ref('/point_of_interest/');
var key = firebase.database().ref().child('point_of_interest').push().key;
var updates = {};
var data = {
città: e.tags["addr:city"],
tipologia: e.tags["amenity"],
indirizzo: e.tags["addr:street"],
nome: e.tags["name"],
lat: e.lat,
lon: e.lon
}
updates['/point_of_interest/'+key] = data;
firebase.database().ref().update(updates);
})
"results" is the response in json format
You could use something like that:
var attrs = ["addr:city", "amenity", "addr:street", "name"];
var labels = ["città", "tipologia", "indirizzo", "nome"]
var data = { };
attrs.forEach((a, i) => {
if (e.tags[a]) { data[labels[i]] = e.tags[a]; }
});
You could even make this more dynamic, if you can query the attribute names and labels from somewhere.

How to correctly find objects by proximity using sequelize.js and PostGIS?

I'm trying to perform a simple ST_Dwithin search using sequelize.js and PostGIS.
In my database I have 3 tables of interest: Users, Neighborhoods and Addresses. All geo data is stored inside addresses table, which has references to users and neighborhoods.
return Neighborhood.findById(id).then(neighborhood => {
return neighborhood.getAddress().then(address => {
return Address.findAll({
where: sequelize.where(
sequelize.fn(
'ST_DWithin',
sequelize.fn(
'ST_Transform',
address.position,
26986),
sequelize.fn('ST_Transform',
sequelize.col('position'),
26986),
distance),
true
)
})
})
}).catch(err => new Error(err));
First I get the address of a neighborhood and then use sequelize.fn to query with PostGIS ST_DWithin function. However this throws an error TypeError: val.replace is not a function. I believe it is something with line address.position. The column position in the table Addresses stores geometry points with type GEOMETRY and srid 4326.
The function works correctly if instead of address.position I hard code something like sequelize.fn('ST_GeomFromText', 'POINT(39.807222 -76.984722)', 4326)
In my case, the geometry(point) attribute is in the User entity. This is what I got working:
var lat = parseFloat(json.lat);
var lng = parseFloat(json.lng);
var attributes = Object.keys(User.attributes);
var distanceAttribute =
sequelize.fn('ST_Distance_Sphere',
sequelize.literal('geolocation'),
sequelize.literal('ST_MakePoint('+lat+','+lng+')'));
var distanceAlias = [distanceAttribute, 'distance'];
attributes.push(distanceAlias);
var query = {
attributes: attributes,
where: sequelize.where(distanceAttribute, {$lte: 100000}),
logging: console.log
}
User.findAll(query)
.then(function(instance){
console.log(instance);
});
Which produces a SQL like this:
SELECT "user_id", "user_name" ... ST_Distance_Sphere(geolocation,
ST_MakePoint(-22.4149023,-47.56513940000002)) AS "distance"
FROM "user" AS "User"
WHERE ST_Distance_Sphere(geolocation,
ST_MakePoint(-22.4149023,-47.56513940000002)) <= 100000;
I think this should work for you too by changing User to Address

Retrieve the index of array

I Have a document like this
...
"users" : [
{
"name":"Bob"
},
{
"name":"Foo"
},
{
"name":"Bar"
},
{
"name":"Boo"
}
]
...
And I want Find the index of Bar
db.coll.find({"users.name":"Bar"})
Can I retrieve the Index of Bar inside Users array? (in this case : 2)
I really don't think the question you are asking leads to the actual answer that you want, but I'll run through a few things to clear up some misconceptions.
Operations such as .find() only returns the "fields present" in the document. It does not create "new results" in any way. The only present exception is the $meta operation which currently only has "textScore" when used with the $text operator for a text search.
There is a positional $ operator, which does "hold" the "matched" position of the first matched array element. But this value itself cannot be "projected" and is only used as a placeholder in order to return an array element at that matching position:
db.collection.find({ "users.name": "Bar" }, { "users.$": 1 })
Which just returns the matching element from the array and no other elements.
In order to get the actual matching position you generally need to inspect the array in code in order to find the matching index position. So retrieve the document and then inspect the array to find the matching index.
If you want to do this over multiple documents then you pretty much do the same thing wrapped in a mapReduce operation. For a full example working with mongoose:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var userFieldSchema = new Schema({
name: String
},{ "_id": false });
var userSchema = new Schema({
users: [userFieldSchema]
});
var User = mongoose.model( "User", userSchema, "users" );
var value = "Bar";
var o = {};
o.map = function() {
emit( this._id, this.users.map(
function(x) { return x.name == value }).indexOf(true)
);
};
o.reduce = function(){};
o.query = { "users.name": value };
o.scope = { value: value };
User.mapReduce(o, function(err,results) {
if ( err ) throw err;
console.log( results );
});
Where the results returned are the _id of the documents matching the condition and the corresponding matching "index" value from the array being tested.
Only operations such as mapReduce and aggregate actually "change" the content of the documents they are working on in the returned result. So there is no present implementation that allows this to be possible with operations such as .find().

Unable to update array fields in mongoosejs

I have a weird issue I can't resolve. I have a Mongoose schema:
Product = new Schema({
title: {
type: String
},
prices: {
type: Array
},
sync: {
type: Boolean
}
...
I use the post save middleware to update a 3rd party site if the sync flag is true. On return of that operation I update the prices array and set sync to false so that it will not result in an endless loop.
Product.post('save', function () {
if(this.sync) {
this.title = "HELLO";
this.prices[0].retail = '24';
this.sync = false;
this.save();
}
});
If I do the above the title and sync fields change but not the prices array. Actually I cannot update any array in my schema. In the above example, the prices array contains about 10 entries - each an object that contains many field including a retail field. I have also tried adding to that array:
this.prices.push({ retail: "10 });
As well as reinit the array:
this.prices = [];
No matter what I do it has no effect. Any non array field can however, be updated.
Any ideas what is going on?
If you don't specify what the schema is within an array field (as in prices), Mongoose treats it as a Mixed field and you have to notify Mongoose of any changes you make to it so that Mongoose knows to save it. Docs here.
So your code should change to:
Product.post('save', function () {
if(this.sync) {
this.title = "HELLO";
this.prices[0].retail = '24';
this.markModified('prices');
this.sync = false;
this.save();
}
});

Categories