Unable to find index for $geoNear query even using index - mongodb

I'm using 3.6.5(mongodb) and trying to get documents near specified location like [-10, 20]...
When I tried get request "http://localhost:3030/ninjas?lng=-80&lat=20" it returns "unable to find index for $geoNear query"
I tried adding index(), changing query and searching official document but, failed.
please help!
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
app.use(bodyParser.json());
mongoose.connect("mongodb://localhost/gpsTest")
.then(() => console.log('Connected to MongoDB...'))
.catch(err => console.error(('Could not connect to MongoDB...\n'), err))
const NinjaSchema = new Schema({
name: {
type: String,
},
rank: {
type: String,
},
available: {
type: Boolean,
default: false
},
geometry: {
type: {
type: String,
default: "Point",
index: '2dsphere'
},
coordinates: {
type: [Number]
}
}
})
NinjaSchema.index({geometry: '2dsphere'});
const Ninja = mongoose.model('ninja', NinjaSchema);
app.post('/ninjas', (req, res) => {
Ninja.create(req.body).then(ninja => {
res.send(ninja);
})
})
app.get('/ninjas', (req, res) => {
Ninja.find({}).where('location').nearSphere({center: {
type: 'Point',
coordinates : [parseFloat(req.query.lng), parseFloat(req.query.lat)],
spherical: true
}}
).then(ninjas => {
res.send(ninjas);
});
})
app.listen(3030, () => {
console.log(`listening port: 3030`);
})
This one is for post request.
{ "name": "test", "rank": "red belt", "available": true,
"geometry" : {"type": "Point", "coordinates": [-80, 27]} }

This is because of typo...
Should change
Ninja.find({}).where('location').nearSphere({center: {...
to
Ninja.find({}).where('geometry').nearSphere({center: {...

Related

How can I see the products per each category with mongoose

this is my schema for storing products using mongoose as below.
const mongoose = require("mongoose");
const mongoosePaginate = require("mongoose-paginate-v2");
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
productImage: {
type: String,
required: true,
},
description: {
type: String,
},
createdAt: {
type: Date,
default: new Date(),
},
deletedAt: {
type: Date,
},
});
productSchema.plugin(mongoosePaginate);
const productModel = mongoose.model("Product", productSchema, "Product");
module.exports = productModel;
and this how I have the schema for storing categories that products are related to
const mongoose = require("mongoose");
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
});
const categoryModel = mongoose.model("Category", categorySchema, "Category");
module.exports = categoryModel;
What I don´t know is how to populate my controller.
getAll: async (req, res) => {
const limitPage = parseInt(req.query.limit, 10) || 10;
const pageChange = parseInt(req.query.page, 10) || 1;
Product.paginate({}, { limit: limitPage, page: pageChange })
.then((result) => {
return res.status(200).json({
message: "GET request to all getAllProducts",
dataCount: result.length,
result: result,
});
})
.catch((err) => {
console.log(err);
res.status(500).json({
error: err,
});
});
},
Please help, I don´t understand why it not being populated and how to see the categories displayed with the categorie they belong to.
You should probably include populate in your query like so:
...
Product.paginate({}, { limit: limitPage, page: pageChange }).populate('category')
...
Note: Are you sure you want to have a 1-1 relation between products and categories. Because this is what you achieve if you set the relation like you did on both schemas. If yes, you should find a way to ensure that this 1-1 relation is enforced each time you save or update objects.

Mongoose text index search returns empty array

I'm trying to query indexes, but I receive an empty array. I can't find what's wrong with my code. I used two methods to create the index: 1) VideoSchema.index() and 2) in the schema itself, both of them don't work. I checked the mongodb and it seems that indexes are created correctly, so I don't know what I do wrong.
const mongoose = require("mongoose");
const VideoSchema = mongoose.Schema(
{
user: {
type: mongoose.ObjectId,
required: true,
ref: "user",
},
title: {
type: String,
maxLength: 100,
text: true,
},
description: {
type: String,
text: true,
},
publishDate: {
type: Date,
},
views: {
type: Number,
default: 0,
},
likes: {
type: Number,
default: 0,
},
dislikes: {
type: Number,
default: 0,
},
comments: [
{
type: mongoose.ObjectId,
ref: "comment",
},
],
urls: {
video_url: {
type: String,
required: true,
},
thumbnail_url: {
type: String,
},
preview_url: {
type: String,
required: true,
},
},
private: {
type: Boolean,
default: 0,
},
category: {
type: String,
default: "",
},
duration: {
type: Number,
required: true,
},
},
{ timestamps: true }
);
// VideoSchema.index({ title: "text", description: "text" });
// export model user with UserSchema
module.exports = mongoose.model("video", VideoSchema);
The query:
const express = require("express");
const router = express.Router();
const Video = require("../model/Video");
router.post("/", (req, res) => {
const query = req.body.query;
Video.find({ $text: { $search: query } }, { score: { $meta: "textScore" } })
.sort({ score: { $meta: "textScore" } })
.exec(function (error, results) {
if (error) return res.status(400).send(error);
res.status(200).json({ results });
});
});
module.exports = router;
As you are fetching data from your Database it´s a good practice and makes the code clearer if you use the 'GET' method. If you do so, there is no need to add the score option to the query since V.4.4
const express = require("express");
const router = express.Router();
const Video = require("../model/Video");
router.get("/", (req, res) => {
const query = req.query.YOUR_QUERY_PARAMETER;
Video.find({ $text: { $search: query }})
.sort({ score: { $meta: "textScore" } })
.exec(function (error, results) {
if (error) return res.status(400).send(error);
res.status(200).json({ results });
});
});
module.exports = router;
If the problem persists:
Try to add the wild card text indexing to see if the problem is within it as follows:
VideoSchema.index({'$**': 'text'});
If so, then drop the collection for a fresh start on the indexing and then append your text indexes like this:
VideoSchema.index({ title: "text", description: "text" });
Create new dummy items and then check again.
Make sure you read the exceptions shown in the MongoDB documentation:
https://docs.mongodb.com/manual/reference/operator/query/text/
It seems that I resolved the problem. I noticed that in the express js the 'query' keyword is used for 'get' request params, so I decided to change this variable to 'search', so now it is like underneath and it is working!
router.get("/", (req, res) => {
const { search } = req.query;
Video.find(
{ $text: { $search: search } },
{ score: { $meta: "textScore" } }
)
.sort({ score: { $meta: "textScore" } })
.exec(function (error, results) {
if (error) return res.status(400).send(error);
res.status(200).json({ results });
});
});
But I've noticed that I'm getting only one video instead of two that contains the 'obs' in the title, so now I will need to deal with that.
Thank you so much for your time and effort!

Mongoose insertMany ignores unique:true

I have the following code
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mydb', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.set('useCreateIndex', true);
mongoose.set('debug', true);
let db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
console.log('connected');
let DocumentSchema = mongoose.Schema({ name: { type: String, unique: true } });
let Document = mongoose.model('Document', DocumentSchema, 'documents');
const docs = [{ name: 'd1' }, { name: 'd1' }, { name: 'd2' }, { name: 'd3' }];
Document.insertMany(docs, (err, docs) => {
if (err) {
console.log(err);
}
else {
console.log('Documents inserted', docs.length);
}
});
});
InsertMany method will add all the objects duplicating them. I cannot find the problem here. Any help is appreciated.
Thanks
Found the issue. When defining the schema you must specify index:true. The documentation stated that if unique:true index is optional. It seems it is not so.
let DocumentSchema = mongoose.Schema({ name: { type: String, unique: true, index: true } });

Why my mongoose request returns a query but not result data, user information in, in my case? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I don't know why it doesn't work for me now, but it did work earlier.
I need to retrieve information from my db. I can easily save data using Model.create but when I want to get data I get:
Query {
_mongooseOptions: {},
_transforms: [],
_hooks: Kareem { _pres: Map {}, _posts: Map {} },
_executionCount: 0,
mongooseCollection: NativeCollection {
collection: Collection { s: [Object] },
Promise: [Function: Promise],
opts: {
bufferCommands: true,
capped: false,
Promise: [Function: Promise],
'$wasForceClosed': undefined
},
name: 'users',
collectionName: 'users',
conn: NativeConnection {
base: [Mongoose],
collections: [Object],
models: [Object],
config: [Object],
replica: false,
options: null,
otherDbs: [],
relatedDbs: {},
states: [Object],
_readyState: 1,
_closeCalled: false,
_hasOpened: true,
plugins: [],
_listening: false,
_connectionOptions: [Object],
client: [MongoClient],
'$initialConnection': [Promise],
_events: [Object: null prototype] {},
_eventsCount: 0,
name: 'test_name',
host: 'cocoondb-shard-00-02-qx9lu.mongodb.net',
port: 27017,
user: 'test',
pass: '1234',
db: [Db]
},
...
I have only one route and use graphql apollo server.
my express route is:
server.js (main file - enterpoint)
import confirmRoute from '../src/routes/confirm';
const app = express();
app.use('/confirm', confirmRoute);
confirm.js
import { Router } from 'express';
import SimpleCrypto from 'simple-crypto-js';
import { env } from '../../environment';
import { User } from '../models/user.model';
const secret = env.TOKEN_SECRET;
const router = Router();
router.get('/*', (req, res) => {
const crypter = new SimpleCrypto(secret);
const id = crypter.decrypt(req.url.slice(1));
const user = User.find({ id }, callback => callback);
res.status(200).send(`Hello, your email confirmed successfully : ${id}`);
})
module.exports = router;
schema
import { Schema, model } from 'mongoose';
const userSchema = new Schema({
firstname: { type: String, required: [false, 'firstname address required'] },
lastname: { type: String, required: [false, 'lastname address required'] },
email: { type: String, required: [true, 'email address required'] },
password: { type: String, required: [true, 'password required'] },
confirmed: { type: Boolean, default: false },
instagram: { type: String, default: "" },
facebook: { type: String, default: "" },
role: { type: String }
}, { timestamps: true });
export const User = model('user', userSchema, 'users');
What am I doing wrong here?
I apologise if my question is silly...
It seems you are not actually executing the query.
Please try one of this solutions to make it work.
Also I used findById, but it does not matter, you can continue to query with findOne also.
Alternative 1: then catch blocks:
router.get("/users/:id", (req, res) => {
User.findById(req.params.id)
.then(doc => {
res.send(doc);
})
.catch(err => {
console.log(err);
return res.status(500).send("something went wrong");
});
});
Alternative 2: callback
router.get("/users/:id", (req, res) => {
User.findById(req.params.id, (err, doc) => {
if (err) {
console.log(err);
return res.status(500).send("something went wrong");
}
return res.send(doc);
});
});
Alternative 3: async/await
router.get("/users/:id", async (req, res) => {
try {
let result = await User.findById(req.params.id);
res.send(result);
} catch (err) {
console.log(err);
return res.status(500).send("something went wrong");
}
});
To apply your case:
router.get("/*", (req, res) => {
const crypter = new SimpleCrypto(secret);
const id = crypter.decrypt(req.url.slice(1));
console.log("id: ", id);
User.findById(req.params.id)
.then(doc => {
console.log("doc: ", doc);
res.status(200).send(`Hello, your email confirmed successfully : ${id}`);
})
.catch(err => {
console.log(err);
return res.status(500).send("something went wrong");
});
});

postman returns empty array

I sent below (raw/json) from postman to mongodb and I received filled img, text but coordinates was empty array "[]"
{
"coordinates": [],
"_id": "5b309b5671903722e073827e",
"date": "2018-06-25T07:35:50.932Z",
"__v": 0
},
Why is this is and how get not empty coordinates array?
Postman
{
"img": "test",
"text": "Meet",
"coordinates": [12, 23]
}
this is my schema
const mongoose = require('mongoose')
const memoSchema = new mongoose.Schema({
img: {
type: String
},
text: {
type: String
},
date: {
type: Date,
default: Date.now
},
coordinates: [Number]
})
module.exports = mongoose.model('Memo', memoSchema)
this is my router
api.post('/', async (req, res) => {
let newMemo = new Memo()
newMemo.img = req.body.img
newMemo.text = req.body.text
newMemo.coordinates = req.body.coordinates
await newMemo.save((err) => {
if(err) return res.status(500).json({ message: 'internal error' })
res.json({ message: 'saved...' })
})
})
I didn't add bodyparser
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())