error when trying to save geojson object using mongoosejs - node.js

If I have the following schema:
var zipSchema = new mongoose.Schema({
zc_code : String,
zc_population : Number,
zc_households : Number,
zc_housevalue : Number,
zc_householdincome : Number,
zc_statecode : String,
zc_state : String,
zc_city : String,
zc_cityname : String,
modified_at : Date,
center: {
type: {type: String},
coordinates: []
}
})
zipSchema.index({ center: '2dsphere' });
And the I try this:
var zipInfo = {
zc_code: '78746',
zc_population: 26928,
zc_households: 10839,
zc_housevalue: 344000,
zc_householdincome: 100571,
zc_latitude: '30.295657',
zc_long: '-97.813727',
zc_statecode: 'TX',
zc_state: 'Texas',
zc_city: 'AUSTIN',
center: {
coordinates: [-73.7567, 42.6525],
type: 'Point'
}
}
Zip.create(zipInfo, function(err) { if (err) console.log(err) })
I get this error every time:
MongoError: location object expected, location array not in correct format
What am I missing. I have searched stackoverflow and seen several different setups for the geojson stuff. I even tried directly copying some stuff from mongoosejs tests and still get errors. I am at a dead end. Any help would be appreciated

It didn't work for me either but I have just fixed it by naming the geometry field: "loc" like here: http://docs.mongodb.org/manual/core/2dsphere/
Here the example I used:
var cableSchema = new mongoose.Schema({
reference: String,
owner: String,
status: String,
setup: String,
model: Number,
loc: {
type: {type:String},
coordinates: Array
}
});

I tried the following with the latest mongoose and it did work for me. Which version are you using? And as for the { type: {type: String } } question, I believe it is because type is also a mongoose keyword type:
var zipSchema = new mongoose.Schema({
zc_code : String,
zc_population : Number,
zc_households : Number,
zc_housevalue : Number,
zc_householdincome : Number,
zc_statecode : String,
zc_state : String,
zc_city : String,
zc_cityname : String,
modified_at : Date,
center: {
type: {type:String},
coordinates: [Number]
}
})
zipSchema.index({ center: '2dsphere' });
var zipInfo = {
zc_code: '78746',
zc_population: 26928,
zc_households: 10839,
zc_housevalue: 344000,
zc_householdincome: 100571,
zc_latitude: '30.295657',
zc_long: '-97.813727',
zc_statecode: 'TX',
zc_state: 'Texas',
zc_city: 'AUSTIN',
center: {
type: 'Point',
coordinates: [-73.7567, 42.6525]
}
}
var Zip = mongoose.model('Zip', zipSchema);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
Zip.create(zipInfo, function(err) {
if (err) console.log(err);
mongoose.disconnect();
})
});
The result was:
> db.zips.find().pretty()
{
"zc_code" : "78746",
"zc_population" : 26928,
"zc_households" : 10839,
"zc_housevalue" : 344000,
"zc_householdincome" : 100571,
"zc_statecode" : "TX",
"zc_state" : "Texas",
"zc_city" : "AUSTIN",
"_id" : ObjectId("522e2df92aacd22e89000001"),
"center" : {
"type" : "Point",
"coordinates" : [
-73.7567,
42.6525
]
},
"__v" : 0
}
> db.zips.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.zips",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"center" : "2dsphere"
},
"ns" : "test.zips",
"name" : "center_2dsphere",
"background" : true,
"safe" : null
}
]
>

Related

MongoDB: executionTimeMillis increased when adding index

I am pretty confused to why making the searched fields to be "index" is making the query "theoretically" slower.
I have a not very big collection of items (6240) and all of them have the following structure.
const SomeSchema = new mongoose.Schema({
data: String,
from: {
type: Number,
},
to: {
type: Number,
},
timeStamp: {
type: Date,
default: new Date()
}
})
SomeSchema.set('toJSON', {
getters: true,
transform: (doc, ret) => {
delete ret.from
delete ret.to
return sanitizeSensitiveProperties(ret)
}
})
export const Some = mongoose.model('Some', SomeSchema, 'somethings')
The strange thing came when after trying to improve the query I changed the schema to be
...
from: {
type: Number,
index: true
},
to: {
type: Number,
index: true
},
...
With this schema I run the following query
db.rolls.find({from: {$lte: 1560858984}, to: {$gte: 1560858984}}).explain("executionStats")
This are the results NOTE THAT THE 1st ONE is the one without index
"executionTimeMillis" : 6,
"totalKeysExamined" : 0,
"totalDocsExamined" : 6240,
"executionTimeMillis" : 15,
"totalKeysExamined" : 2895,
"totalDocsExamined" : 2895,
Does this result make any sense, or is just the mongo .explain() function messing around?
As you can see I am using the Mongoose Driver in the version ^5.5.13 and I am using Mongo in the version 4.0.5

selecting data from several collections after finding the proper id in documents

I have an almost working solution, but I believe my solution is bad programmed and I don't know how to make it better. Maybe it should be done with mongoose population, but I can't figure out how it works and how to adjust my code.
I have 2 collections: author and books. They are imported from MySQL with data - so I can't change the structure.
author:
{ "_id" : ObjectId("59492addd80eb0f9c1b42fd9"), "id_a" : 1, "name" : "Agatha Christie", "gender" : "female", "born" : 1890, "birthplace" : "England", "genre" : "crime"
}
{ "_id" : ObjectId("594935e1d80eb0f9c1b42fdb"), "id_a" : 2, "name" : "Stephen King", "gender" : "male", "born" : 1947, "birthplace" : "U.S.", "genre" : "horror" }
books:
{ "_id" : ObjectId("59492cd1d80eb0f9c1b42fda"), "id_b" : 1, "title" : "Murder on the Orient Express", "id_a" : 1, "pub_date" : 1934, "publisher" : "Collins Crime Club",
"pages" : 256, "description" : "Hercule Poirot, the internationally famous detective, boards the Orient Express (Simplon-Orient-Express) in Istanbul. The train is unus
ually crowded for the time of year. Poirot secures a berth only with the help of his friend Monsieur Bouc, a director of the Compagnie Internationale des Wagons-Lits. W
hen a Mr. Harris fails to show up, Poirot takes his place. On the second night, Poirot gets a compartment to himself..." }
{ "_id" : ObjectId("59493779d80eb0f9c1b42fdc"), "id_b" : 2, "title" : "The A.B.C. Murders", "id_a" : 1, "pub_date" : 1936, "publisher" : "Collins Crime Club", "pages" :
256, "description" : "The novel follows the eponymous murders and their investigation as seen by Arthur Hastings, Poirot's old friend. Poirot receives typed letters si
gned by A.B.C. In each is given the date and location of the next murder. A.B.C. moves alphabetically: Alice Ascher is a tobacco shop owner killed in her shop in Andove
r, Betty Barnard is a flirty waitress killed in Bexhill, and Sir Carmichael Clarke is a wealthy man killed at his home in Churston..." }
{ "_id" : ObjectId("59493858d80eb0f9c1b42fdd"), "id_b" : 3, "title" : "The Shining", "id_a" : 2, "pub_date" : 1977, "publisher" : "Doubleday", "pages" : 447, "descripti
on" : "The Shining mainly takes place in the fictional Overlook Hotel, an isolated, haunted resort located in the Colorado Rockies. The history of the hotel, which is d
escribed in backstory by several characters, includes the deaths of some of its guests and of former winter caretaker Delbert Grady, who succumbed to cabin fever and ki
lled his family and himself..." }
I want to find with author's name his id in the collection author and use his id to find all his books in the collection books. But the json-result should be a combination of selected field from both collections. For example I search for Agatha Christie and want get following selected fields as one json-object (name and genger from author + title and description from books as one object) Desired Api result in postman:
[ {
"name": "Agatha Christie",
"gender": "femail",
"title" : "Murder on the Orient Express",
"description" : "Hercule Poirot, the internationally famous detective, boards the Orient Express (Simplon-Orient-Express) in Istanbul...."
},
{
"name": "Agatha Christie",
"gender": "femail",
"title" : "The A.B.C. Murders",
"description" : "The novel follows the eponymous murders and their investigation as seen by Arthur Hastings, Poirot's old friend..."
}]
here is my code:
api.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
mongoose.connect('mongodb://localhost/books');
var db = mongoose.connection;
db.on('connected', function() {
console.log('MongoDB connection successful');
});
Author = require('./models/books');
Book = require('./models/books');
app.post('/api/Books', function(req, res){
Author.getAuthor({name : req.body.name}, 10, function(err, data){
if (err){
throw err;
}
var tmp = data[0].id_a;
Book.getBook({id_a : tmp}, 10, function(err, data2){
if (err){
throw err;
}
var result = [data, data2];
console.log(result);
res.json(result);
});
});
});
app.listen(3000);
console.log('server started and waits on port 3000');
books.js
var mongoose = require('mongoose');
var authorSchema = mongoose.Schema({
id_a:{
type: Number,
required: true
},
name:{
type: String,
required: true
},
gender:{
type: String,
required: true
},
born:{
type: Number,
required: true
},
birthplace:{
type: String,
required: true
},
genre:{
type: String,
required: true
}},
{ collection: 'author'}
);
var booksSchema = mongoose.Schema({
id_b:{
type: Number,
required: true
},
title:{
type: String,
required: true
},
id_a:{
type: Number,
required: true
},
pub_date:{
type: Number,
required: true
},
publisher:{
type: String,
required: true
},
pages:{
type: Number,
required: true
},
description:{
type: String,
required: true
}},
{ collection: 'books'}
);
var Author = module.exports = mongoose.model('author', authorSchema);
var Book = module.exports = mongoose.model('books', booksSchema);
module.exports.getAuthor = function(query, limit, callback){
Author.find(query, {'_id': 0}).select('id_a').limit(limit).exec(callback);
}
module.exports.getBook = function(query, limit, callback){
Book.find(query).select('-_id id_a title').limit(limit).exec(callback);
}
With my app I can find the proper books to particular author, but my result is without author's name and gender - I don't know how to do it. Also I make a request with nested functions - there might be much better solution for it. My solution feels very dirty. How can I improve my code and get data from both collections? A working adjusted example would be realy great!
First you have to add those changes:
model:
var booksSchema = mongoose.Schema({
...
},
{ collection: 'books', toJSON: { virtuals: true } })
// Foreign keys definitions
// http://mongoosejs.com/docs/populate.html#populate-virtuals
booksSchema.virtual('author', {
ref: 'author',
localField: 'id_a',
foreignField: 'id_a',
justOne: true // for many-to-1 relationships
});
module.exports.getAuthor = function (query) {
return Author.findOne(query).exec();
}
// this help you get books with author
module.exports.getBook = function (query) {
return Book.find(query)
.populate('author')
.exec();
}
app code:
app.post('/api/Books', function (req, res) {
Author.getAuthor({ name: req.body.name }, 10)
.then(author => {
return Book.getBook({ id_a: author.id_a });
})
.then(result => {
console.log(result);
res.json(result);
})
.catch(error => {
// TODO:
});
});
result should be:
[{...book info,...author info }]
I hope this help you

How to update array in mongodb using mongoose

when i try to update it dose not throw back any error it goes OK but when i check my datebase nothing i their updated nothing is modified pls help
this is my db
{
"_id" : ObjectId("56651f0e4905bd041cad0413"),
"creator" : ObjectId("566299dd17990464160ae27a"),
"content" : "this is my joke 2",
"created" : ISODate("2015-12-07T05:54:22.858Z"),
"__v" : 15,
"comments" : [
{
"posteruserId" : "5665e6867185d87c1e71dbdc",
"postedBy" : "lawrence nwoko",
"postterscomment" : "good joke",
"_id" : ObjectId("56660745f644c2501116acce")
},
{
"posteruserId" : "5665e6867185d87c1e71dbdc",
"postedBy" : "lawrence nwoko",
"postterscomment" : "good joke",
"_id" : ObjectId("56660b6d33c245c012104fdc")
}
]
}
this is my schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var JokesSchema = new Schema({
creator: {type: Schema.Types.ObjectId, ref: 'User'},
content: String,
created:{type:Date, default: Date.now},
comments: [{
text: String,
postedBy: String,
posteruserId :String,
date: String,
postterscomment:String
}]
})
module.exports = mongoose.model('Jokes_db', JokesSchema)
here i my post funtion
api.post('/update', function(req, res) {
// Joke.findById("56651f0e4905bd041cad0413", function (err, meeting) {
Joke.update({_id: "5665e6867185d87c1e71dbdc", 'comments._id' : "56660745f644c2501116acce"},
{'$set': {
'comments.$.postterscomment': "working"
}},
function(err, numAffected) {
if(err){
console.log(err)
}else{
res.json(numAffected)
}
}
);
});
It has been three days of trying to fix this problem but by his grace I have done it without help the problem user that I was not using the right id to make the query thanks for your help guys I hope this helps another user
api.post('/editecomments', function(req, res) {
Joke.update({_id: "56651f0e4905bd041cad0413", 'comments._id' : "56660745f644c2501116acce"},
{'$set': {'comments.$.postterscomment': 'working'}},
function(err, numAffected) {
if(err){
console.log(err)
}else{
res.json(numAffected)
}
}
);
});

Mongoose & float values

My lat & lng numbers are being converted to strings. My section integers are still the correct data type of Number. How do I set up model so that I can get my lat & lng back out as Float rather than String?
I'm storing latLng data in my db. Right now I have my data type set to Number for lat & lng. When I check out my db I see this:
{
"_id" : ObjectId("563bd98a105249f325bb8a7e"),
"lat" : 41.8126189999999980,
"lng" : -87.8187850000000054,
"created" : ISODate("2015-11-05T22:34:50.511Z"),
"__v" : 0,
"section" : 0,
}
But when I get my data back out using express I get this:
{
"_id": "563bd98a105249f325bb8a7e",
"lat" : "41.8126189999999980",
"lng" : "-87.8187850000000054",
"__v": 0,
"section" : 0,
"created" : "2015-11-05T22:34:50.511Z",
}
My model:
var WaypointSchema = new Schema({
lat: {
type: Number
},
lng: {
type: Number
},
section: {
type: Number
}
created: {
type: Date,
default: Date.now
}
});
mongoose.model('Waypoint', WaypointSchema);
Express controller:
exports.list = function(req, res) {
Waypoint.find().sort('-created').populate('user', 'displayName').exec(function(err, waypoints) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(waypoints);
}
});
};
While the mongoDB fully supports float type, the mongoose supports only type of Number which is integer. If you try to save to mongoDB float number using mongooses type of Number it will be converted to string.
To sort this out, you will need to load some plugin for mongoose which will extend its value types. There are some plugins which work best with currencies or dates, but in your case I would use https://www.npmjs.com/package/mongoose-double.
Your model after changes would look something like this:
var mongoose = require('mongoose')
require('mongoose-double')(mongoose);
var SchemaTypes = mongoose.Schema.Types;
var WaypointSchema = new Schema({
lat: {
type: SchemaTypes.Double
},
lng: {
type: SchemaTypes.Double
},
section: {
type: Number
}
created: {
type: Date,
default: Date.now
}
});
mongoose.model('Waypoint', WaypointSchema);
Hope it helps.
As of the current version of mongoose (v5.12.6), It supports Decimal128 which can be used for this.
var mongoose = require('mongoose');<br>
var Schema = mongoose.Schema;<br>
var Waypoint = new Schema({<br>
lat: {<br>
type: SchemaTypes.Double<br>
},<br>
lng: {<br>
type: SchemaTypes.Double<br>
},<br>
section: {<br>
type: Number<br>
}<br>
point: {<br>
type: [Number],<br>
index: '2d'<br>
},<br>
}, {<br>
timestamps: true<br>
})<br>
event.index({<br>
Point: '2dsphere'<br>
});<br>
module.exports = mongoose.model('Waypoint', Waypoint);<br>
waypoint.save(point: [parseFloat(values.latitude), parseFloat(values.longitude)],)

NodeJS + Mongoose + Backbone.Marionette nested Collection templating

all
I'm developing an application that store my multimedia catalog, I've JSON collection like this :
{ "_id" : ObjectId( "5142f55394474e2aac000001" ),
"contentType" : "binary/octet-stream",
"length" : 2732376,
"chunkSize" : 262144,
"uploadDate" : Date( 1363342677601 ),
"metadata" : {
"TIT2" : "Chase The Blues (Cameron McVey Remix)",
"TPE1" : "Terranova",
"TRCK" : "1/13",
"TALB" : "!K7",
"TPOS" : "1/1",
"TDRC" : "2000-06",
"TCON" : [
"Electronica",
"Trip-Hop" ],
"COMM" : [
"Chillout",
"Love",
"German",
"Berlin",
"2000s",
"Female Vocalists",
"Male Vocalists" ],
"TMED" : "CD",
"TMOO" : "Chill",
"TDOR" : "2000-06",
"TSO2" : "Various Artists",
"TPE2" : "Various Artists",
"TCMP" : "1",
"TSOP" : "Terranova",
"TIT1" : "Electronica",
"TPUB" : "Sinedín Music",
"TLAN" : "eng",
"TYER" : [
"2000" ],
},
"md5" : "617401af615ac0c6cb1dee9a3f1b99e6",
"origin" : "Chase The Blues.109eb5ab5105a1caa505a26657f7f9a8.mp3",
"evolution" : null,
"insertDate" : Date( 1336662308000 ),
"tagSource" : "MusicBrainz",
"mediainfo" :
{ "Format" : "MPEG Audio",
"Format version" : "Version 1",
"Format profile" : "Layer 3",
"Duration" : "3mn 47s",
"Bit rate mode" : "Constant",
"Bit rate" : "96.0 Kbps",
"Channel(s)" : "1 channel",
"Sampling rate" : "44.1 KHz",
"Compression mode" : "Lossy",
"Stream size" : "2.60 MiB (100%)",
"Language" : "English"
}
}
so, as you can see, there are "metadata" and "mediainfo" array in the document
in the models.js , in the client side, I've rewrite the model parse function like this
var Audio_Model = Backbone.Model.extend({
idAttribute: "_id",
url: 'AudioModel',
urlRoot: 'AudioModel' ,
parse: function(response) {
// Check if response includes some nested collection data...
if (_.has(response, 'metadata')){
// Check if this model has a property called metadata
if (!_.has(this, 'metadata')) { // It does not...
// So instantiate a collection and pass in raw data
this.metadata = new Audio_Collection_Metadata(response.metadata);
} else {
// It does, so just reset the collection
this.metadata.reset(response.metadata);
}
delete response.metadata;
}
// Check if response includes some nested collection data...
if (_.has(response, 'mediainfo')){
// Check if this model has a property called mediainfo
if (!_.has(this, 'mediainfo')) { // It does not...
// So instantiate a collection and pass in raw data
this.mediainfo = new Audio_Collection_Mediainfo(response.mediainfo);
} else {
// It does, so just reset the collection
this.mediainfo.reset(response.mediainfo);
}
delete response.mediainfo;
}
return response;
}
});
so I've created two separate collection of 'metadata' and 'mediainfo'
the problem that I've is how to render 'metadata' and 'mediainfo' in html template because in 'mediainfo' and 'metadata' collection the key, values are not fixed and in 'metadata' some keys are array of values and the number of item in the array are not fixed
I've created backbone.marionette.itemview and compositeview for these two collections but I don't know how to render
Plase, someone have a solutions ?
Best Regards
finally I've fixed the problem myself with a data normalization, this is the new mongoose schema adopted :
var TagSchema = new mongoose.Schema({
value : {type : String, default: '', required: true}
});
var MetadataSchema = new mongoose.Schema({
name : {type: String, default: '', required : true},
values: [TagSchema]
});
var MediainfoSchema = new mongoose.Schema({
name : {type: String, default: ''},
value: {type: String, default: ''}
});
var StreamSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
TIT2: {type : String, default: '', required: true},
metadata: [MetadataSchema],
mediainfo:[MediainfoSchema]
});
so that with sequence of CollectionView and CompositeView I can browse the entire model
Hope this can help someone

Resources