Mongoose unable to perform $near query on array of locations - node.js

I've tried looking for solutions and I've read parts of the documentation for the $near and $geoNear queries but I have not been successful.
var userSchema = new Schema({
zipcode : {
formatted : {type : String, required : false, default : ""},
geo : { type: [Number], default: [0,0]} // long, lat
}
});
userSchema.index({"zipcode.geo" : '2d'});
ON A DIFFERENT FILE
var locationSchema = new Schema({
formatted : {type : String, unique : false, required : true},
geo : { type: [Number], default: [0,0]}
});
locationSchema.index({geo: '2d'});
var storeSchema = new Schema({
locations : [locationSchema],
});
On my controller
let nearQuery = {
$near : [ user.zipcode.geo[0], user.zipcode.geo[1]],
spherical: true,
$maxDistance: 7000
}
Stores.find(locations : nearQuery).exec(function(error, doc) {
});
But i end up getting the error - "Error: Can't use spherical with Array."
When I remove
spherical : true
I get the error - " planner returned error: unable to find index for $geoNear query"
I know i am doing something wrong, I just cant figure out how to fix it. How can I fix this? or What is the best way of doing this?
Thank you in advance.

Turns out I was using the wrong syntax for the query and was trying to run the query on the locations field, while I should have done it on the locations.geo field.
https://docs.mongodb.com/manual/tutorial/query-a-2d-index/

Related

Inserting array in mongodb in nodejs

i have two variable name and place
var name = 'ram';
var place = ['agra','delhi'];
my Schema is like
var Person= new Schema({
about :
{
name: {type : String},
place: {type : String}
}
,
});
I used query
var person = new Person({
about :
{
name : name,
place : place
}
});
person.save(function(){});
but the problem is that place store as a string in database
name : 'ram',
place : 'agra,delhi'
,so when i applying a query for searching place='agra' ,it gives null output.
But when i search place='agra,delhi' it produces result.
I want that this place store as array in database like
name : 'ram',
place : ['agra','delhi']
Please help me in this.
Change your schema to store places as array
var Person= new Schema({
about : [
{
name: {type : String},
places: [{type : String}]
}
],
});

MongoDB default values are not saved, instead re-calculated at runtime

I'm building a simple REST app on the Yeoman Express MVC generator with MongoDB.
This is my MongoDB/Mongoose model (updated with complete update.js model):
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var UpdateSchema = new Schema({
title: String,
text: String,
authors: String,
url: String,
imageUrl: String,
dateCreated: { type: Date, default: Date.now },
reloadNeeded: { type: Boolean, default: true }
});
mongoose.model('Update', UpdateSchema);
This is what the data looks like in the Mongo client:
> db.updates.find();
{ "_id" : ObjectId("5476453f8920d05ecdef4eec"), "title" : "Hello World", "text" : "yoda yoda" }
{ "_id" : ObjectId("547653748920d05ecdef4eed"), "title" : "Hihi", "text" : "mookie" }
And this is the JSON output from my Express app:
[
{"_id":"5476453f8920d05ecdef4eec","title":"Hello World","text":"yoda yoda","reloadNeeded":true,"dateCreated":"2014-11-27T10:50:10.078Z"},
{"_id":"547653748920d05ecdef4eed","title":"Hihi","text":"mookie","reloadNeeded":true,"dateCreated":"2014-11-27T10:50:10.078Z"}
]
So, dateCreated and reloadNeeded are set at runtime - but I'd rather want them set (and persisted) when I create the documents. What's going on?
Update: seems like values are persisted if I create from Mongoose rather than the MongoDB shell.
Do you use mongoose for data model? If it so, default values will be created on document construction http://mongoosejs.com/docs/2.7.x/docs/defaults.html
Anyway I assume the reason is in defaults

Mongodb Full text search, get the matched string in the document

I am trying to implement FTS feature with node and mongdodb backend. In the search result, I would also like to project a new field, i.e the matched string in the document. This would give it a google like feel. Has anyone got ideas on this without having write lots of own custom functions?
The schema looks like this
var version = new mongoose.Schema({
name: String,
owner: String,
reviewer: String,
date_of_modification: Date,
comments: String,
hints: [String],
global: Boolean,
**content: { type: [String], index: true }**
version_no: Number,
});
var artifactSchema= new mongoose.Schema({
pid : String,
trashed : Boolean,
baseline : Number,
versions : [version],
});
I would like to create an index on the content field of Version model.
I know its a little late but recently I did it with MEAN+angucomplete
AngularJS Query e.g. http://localhost:8080/api/search?s=
Express Query
router.route('/search')
.get(function(req, res) {
Dept.aggregate(
{ $match : { 'Product.name' : new RegExp(query, 'gi') } },
{ $project : { name : 1, _id : 1, 'Product.name' : 1, 'Product._id' : 1} },
{ $unwind : "$Product" },
{ $group : {
_id : "$_id",
Category : { $addToSet : "$name"},
Product : { $push : "$Product"}
}}
)
});
Angucomplete Markup
<div angucomplete-alt id="depts"
placeholder="Click Here to Search across Whole Store"
pause="300"
selected-object="selectedDepts"
remote-url="http://localhost:8080/api/search?s="
remote-url-data-field="Departments"
remote-url-response-formatter="responseFormatted"
search-fields="name"
title-field="name"
minlength="1"
maxlength="20"
description-field="description"
override-suggestions="true"
match-class="highlight"
autocapitalize="on" autocorrect="off" autocomplete="off"
input-class="form-control form-control-small"
class="col-lg-8"
ng-pattern="/^[A-Za-z]+$/"
docs-search-input-focus
>
</div>

Mongoose fail to set ref -Schema.Types.ObjectId- to other document

I'm trying to save a document with mongoose according to the doc http://mongoosejs.com/docs/populate.html
First I call parent.save and inside the callback of parent.save I use child.save.
But when I check parent.childs I can see that no child has been added.
The parent schema is Home :
var HomeSchema = new Schema({
password : String,
draft : { type: Boolean, default: true },
edited : { type: Boolean, default: false },
guests : [{type : Schema.Types.ObjectId, ref : 'Guest'}],
_event : {type : Schema.Types.ObjectId, ref : 'Event'}
});
the child schema is Guest :
var GuestSchema = new Schema({
_home : {type : Schema.Types.ObjectId, ref : 'Home'},
firstname : String,
lastname : String,
coming : { type: String, default: 'dnk-coming' },
phone : String,
email : String,
address : String,
edited : { type: Boolean, default: false },
draft : { type: Boolean, default: true }
});
To avoid any misunderstanding, you have to know that this two Schema are included in my user schema :
var userSchema = mongoose.Schema({
homes:[homeSchema.HomeSchema],
events:[eventSchema.EventSchema],
guests:[eventSchema.guestSchema],
});
Now you should have all the required informations to completly understand the execution :
UserModel.findById(user._id, function(err, userFound) {
if (!err) {
/* cleaning draft*/
userFound.homes = that.clean(userFound.homes);
/* setting draft */
var HomeModel = mongoose.model("Home");
var homeModel = new HomeModel();
homeModel.draft = true;
if (userFound.homes === null) {
userFound.homes = [];
}
homeModel.save(function(err) {
if (!err) {
var GuestModel = mongoose.model("Guest");
var guestModel = new GuestModel();
guestModel._home = homeModel._id;
guestModel.save(function(err) {
if (!err) {
// #ma08 : According to the doc this line should'nt be required
//homeModel.guests.push(guestModel._id); so when I use this obviously the id is correctly set but when I try a populate after saving the populate do not work
userFound.homes.push(homeModel);
userFound.guests.push(guestModel);
userFound.save(function(err) {
if (!err) {
successCallback();
}
else {
errorCallback();
}
});
}
});
}
});
This treatement doesn't result in any error. But it doesn't work as intended when I stringify the user.guests I get :
guests:
[ { coming: 'dnk-coming',
edited: false,
draft: true,
_id: 53dcda201fc247c736d87a95,
_home: 53dce0f42d5c1a013da0ca71,
__v: 0 }]
wich is absolutly fine I get the _home id etc...
Then I stringify the user.homes and I get :
homes:
[ { draft: true,
edited: false,
guests: [],
_id: 53dce0f42d5c1a013da0ca71,
__v: 0 } ]
According to the doc guests should be setted, but it's not <-- this is my issue. Please help me to figure out what I'm doing wrong. I could set it manualy but according to the doc it's not suppose to work this way I think.
guestModel.save(function(err) {...
this is wrong because you are embedding the guests in the userSchema.
So skip the guestModel.save and just push the guestModel in userFound
An embedded document can never a reference. You can't point to it without obtaining the parent document. So you can't do both embedding and keeping a ref to the embedded document. You should choose between either embedding or adding a ref.
My suggestion would be to design your schemas like this. Store guests in a separate collection. Store the ref to guest in user and home schemas. If you want to store some relationship data you can store along with the ref like [{guestId:{type:Schema.Types.ObjectId,ref:'Guest'},field1:{type:...},field2:{...}..] and if you just want the ref [{type:Schema.Types.ObjectId,ref:'Guest'}]

Using sparse: true still getting MongoError: E11000 duplicate key error

Schema (../models/add.js)
var addSchema = new Schema({
name: {type: String, unique: true, sparse: true},
phone: Number,
email: String,
country: Number
});
module.exports = mongoose.model('Contact', addSchema);
add-manager.js
var Add = require('../models/add.js');
var AM = {};
var mongoose = require('mongoose');
module.exports = AM;
AM.notOwned = function(country, callback)
{
Add.update({country: country}, {country: country}, {upsert: true}, function(err, res){
if (err) callback (err);
else callback(null, res);
})
}
news.js
// if country # is not in the database
AM.notOwned(country, function(error, resp){
if (error) console.log("error: "+error);
else
{
// do stuff
}
})
error:
MongoError: E11000 duplicate key error index: bot.contacts.$name_1 dup key: { : null }
After seeing the error message, I googled around and learned that when the document is created, since name isn't set, its treated as null. See Mongoose Google Group Thread The first time AM.notOwned is called it will work as there isn't any documents in the collection without a name key. AM.notOwned will then insert a document with an ID field, and a country field.
Subsequent AM.notOwned calls fails because there is already a document with no name field, so its treated as name: null, and the second AM.notOwned is called fails as the field "name" is not set and is treated as null as well; thus it is not unique.
So, following the advice of the Mongoose thread and reading the mongo docs I looked at using sparse: true. However, its still throwing the same error. Further looking into it, I thought it may be the same issue as: this, but setting schema to name: {type: String, index: {unique: true, sparse: true}} doesn't fix it either.
This S.O. question/answer leads me to believe it could be caused by the index not being correct, but I'm not quite sure how to read the the db.collection.getIndexes() from Mongo console.
db.contacts.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "bot.contacts",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"name" : 1
},
"unique" : true,
"ns" : "bot.contacts",
"name" : "name_1",
"background" : true,
"safe" : null
}
]
What can I do to resolve this error?
You need to drop the old, non-sparse index in the shell so that Mongoose can recreate it with sparse: true the next time your app runs.
> db.contacts.dropIndex('name_1')

Resources