Mongoose can't recognize my 2dsphere index - javascript

I'm trying to add 2dSphere index for my field startLocation exists in tourSchema. Here how it looks below
startLocation: {
type: {
type: String,
default: 'Point',
enum: ['Point']
},
coordinates: [Number],
address: String,
description: String
}
And you can also see below what and how I've added indexes on this Schema
tourSchema.index({price:1,ratingsAverage:-1});
tourSchema.index({slug:1});
tourSchema.index({ startLocation: '2dsphere' });
Unfortunately Mongodb can't recognize startLocation index. Using Mongo Compass , I'm able to see all indexes that I've created except startLocation:'2dsphere'.
Here is the error that postman gives me below when I send request to getDistances method in controller:
{
"status": "error",
"error": {
"operationTime": "6791492473605586945",
"ok": 0,
"errmsg": "$geoNear requires a 2d or 2dsphere index, but none were found",
"code": 27,
"codeName": "IndexNotFound",
"$clusterTime": {
"clusterTime": "6791492473605586945",
"signature": {
"hash": "4LYCSBslSoLAoqj93bLXmpubBxs=",
"keyId": "6779443539857113090"
}
},
"name": "MongoError",
"statusCode": 500,
"status": "error"
},
"message": "$geoNear requires a 2d or 2dsphere index, but none were found",
"stack": "MongoError: $geoNear requires a 2d or 2dsphere index, but none were found\n at Connection.<anonymous> (C:\\Users\\timuc\\Downloads\\starter\\starter\\node_modules\\mongodb-core\\lib\\connection\\pool.js:443:61)\n at Connection.emit (events.js:223:5)\n at processMessage (C:\\Users\\timuc\\Downloads\\starter\\starter\\node_modules\\mongodb-core\\lib\\connection\\connection.js:364:10)\n at TLSSocket.<anonymous> (C:\\Users\\timuc\\Downloads\\starter\\starter\\node_modules\\mongodb-core\\lib\\connection\\connection.js:533:15)\n at TLSSocket.emit (events.js:223:5)\n at addChunk (_stream_readable.js:309:12)\n at readableAddChunk (_stream_readable.js:290:11)\n at TLSSocket.Readable.push (_stream_readable.js:224:10)\n at TLSWrap.onStreamRead (internal/stream_base_commons.js:181:23)"
}
I tried to add point: '2dsphere' which was recognized by mongodb but I'm not satisfied. Because when I send request to method in controller that returns success but with empty array.
Here is the method which was triggered in controller:
exports.getDistances = catchAsync(async (req, res, next) => {
const { latlng, unit } = req.params;
const [lat, lng] = latlng.split(",");
if (!lat || !lng) {
new AppError( "Please provide latitude and longitude in the format lat,lng", 400);
}
const distances = await Tour.aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [lng * 1, lat * 1]
},
distanceField: "distance"
}
}
]);
res.status(200).json({
status: "success",
data: {
data: distances
}
});
});
also from router you can see how I send the request URL below
tourRouter.route('/distances/:latlng/unit/:unit').get(tourController.getDistances);

I strongly believe that you are not using the proper collection. This is working for MongoDB 4.2.
Creating the index:
db.location.createIndex({
startLocation: "2dsphere"
})
Indexes of that collection:
db.location.getIndexes()
[{
"v": 2,
"key": {
"_id": 1
},
"name": "_id_",
"ns": "stackoverflow.location"
}, {
"v": 2,
"key": {
"startLocation": "2dsphere"
},
"name": "startLocation_2dsphere",
"ns": "stackoverflow.location",
"2dsphereIndexVersion": 3
}
]
Inserting some data:
db.location.insert({
startLocation: {
type: "Point",
coordinates: [40, 5],
address: "Hellostreet 1",
description: "Hello"
}
})
Aggregate the collection:
db.location.aggregate([{
$geoNear: {
near: {
type: 'Point',
coordinates: [41, 6]
},
distanceField: 'distance'
}
}
])
The result:
{
"_id" : ObjectId("5e404cdd13552bde0a0a9dc5"),
"startLocation" : {
"type" : "Point",
"coordinates" : [
40,
5
],
"address" : "Hellostreet 1",
"description" : "Hello"
},
"distance" : 157065.62445348964
}

Related

$divide is mongoose is giving "Cast to Number failed for value"

Here i am trying to update the 'rating' field of my document by taking average of previously existing value of the rating field and newly sent rating value.
this is my rating field specification in the model
rating: {
type: Number,
min: 0,
max: 5,
required: true,
},
this is my request body and controller function
const { newRating, bookID, userName, comment } = req.body;
const updateRating = await Book.findByIdAndUpdate(
{ _id: bookID },
{
rating: { $divide: [{ $inc: { rating: Number(newRating) } }, 2] },
$inc: { numOfRatings: 1 },
},
{ new: true }
);
and i am using postman to send client side data
here for example the rating field has previously set value of 4.1 and i am sending 5 as new rating in req.body then i want the rating field to have an updated value of 4.55 ((4.1+5)/2)
and this is the output i am getting in postman
{
"message": "Cast to Number failed for value "{ '$divide': [ { '$inc': [Object] }, 2 ] }" (type Object) at path "rating"",
"stack": "CastError: Cast to Number failed for value "{ '$divide': [ { '$inc': [Object] }, 2 ] }" (type Object) at path "rating"\n at model.Query.exec (D:\Programs\VS Code\Web Development\lmsbackend\node_modules\mongoose\lib\query.js:4891:21)\n at model.Query.Query.then (D:\Programs\VS Code\Web Development\lmsbackend\node_modules\mongoose\lib\query.js:4990:15)\n at processTicksAndRejections (node:internal/process/task_queues:96:5)"
}
i tried few things seeing mongodb solutions but it is not working out for me. Thank you in advance.
I hope this will work:
const updateRating = await Book.findByIdAndUpdate(
{ _id: bookID },
[{
"$set": {
"rating": { "$divide": [{ "$sum": ["$rating", 5] }, 2] },
"numOfRatings": { "$sum": ["$numOfRatings", 1 ] }
}
}],
{ new: true }
);
$divide is only available for Aggregation framework, so you need to change your update (second) input like this:
await Book.findByIdAndUpdate({
_id: bookID
},
[
{
"$set": {
"rating": { "$divide": [{ "$sum": ["$rating", Number(newRating)] }, 2] },
"numOfRatings": { "$sum": ["$numOfRatings", 1 ] }
}
}
])
Working example

How to fetch particular documents in elasticsearch index

I want to fetch all the data of the corresponding particular field, and have a response of the elastic search.
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 35,
"relation": "eq"
},
"max_score": 0.44183275,
"hits": [
{
"_index": "allevents",
"_type": "_doc",
"_id": "jQPDaG0BcOh3oggcguoV",
"_score": 0.44183275,
"_source": {
"category": "sessions",
"contentid": "KqRLj2lWZ3",
"clientname": "omkarpathlab",
------------------
}]
I tried search function it returning an error.
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: 'aaa',
log: 'trace',
apiVersion: '7.1'
});
client.search({
"size": 20,
"query": {
"query_string": {
"default_field": "clientname",
"query": "omkarlab"
}
}
}).then((res) => {
console.log("resultData", res);
}, (err) => {
console.log("err", err);
});
enter code here
Error showing:
{ Error: [illegal_argument_exception] request [/_search] contains unrecognized parameter: [query]
Please suggest me how to solve this kind of problem.
You should specify your field under default_field, not the value you are looking for. The field you are trying to query is clientname in your case, and the value you are looking for is omkarpathlab. So your query should be as follows:
"query": {
"query_string": {
"default_field": "clientname",
"query": "omkarpathlab"
}
}
edit. But your query inside of the body property:
client.search({
"size": 20,
"body": {
"query": {
"query_string": {
"default_field": "clientname",
"query": "omkarlab"
}
}
}
}).then((res) => {
console.log("resultData", res);
}, (err) => {
console.log("err", err);
});
You can use below code to connect to elasticsearch. I have tested it on 5.6 version
'use strict'
const { Client } = require('#elastic/elasticsearch')
const client = new Client({ node: 'http://XXX:9200' })
async function run () {
// Let's search!
const { body } = await client.search({
index: 'XXX',
type : 'XXX',
body: {
query: {
match_all: {}
}
}
})
console.log(body.hits.hits)
}
run().catch(console.log)
Code is a sample from https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/search_examples.html site.
for search documentation check below link
https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#_search

How to query an array in mongodb

Was trying to filter an array with another condition to query my MongoDB database
I have tried using the elemMatch to match exactly with the query, but it not working out.
Here is my code
my shipment schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const ShipmentSchema = new Schema({
warehouseNo:{
type: String,
ref: 'users.unitNo'
},
packages:[
{
category:{
type: String
},
quantity:{
type: String
},
description:{
type: String
},
trackingno:{
type: String,
},
date:{
type: Date,
default: Date.now
},
length:{
type: Number
},
width:{
type: Number
},
height:{
type: Number
},
weight:{
type: Number
},
fee:{
type: Number,
},
status: {
type: String,
default: "In warehouse"
},
},
],
shippingMode:{
type: String,
},
date:{
type: Date,
default: Date.now
}
});
module.exports = Shipments = mongoose.model('shipments', ShipmentSchema);
Here is my node js.
// #route GET api/user/package
// #desc Get all package
// #access Private
router.get('/package',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {};
Shipments.findOne({warehouseNo : req.user.unitNo})
.then(shipments => {
if (shipments.packages.length === 0) {
errors.nopackages = 'There are no packages for you yet';
return res.status(404).json(errors);
}
res.json(shipments.packages);
})
});
The code above bring every record in my mongoddb, but if i tried the below, where i ask it to fillter by package status. i got a code crash error
// #route GET api/user/package
// #desc Get all package
// #access Private
router.get('/package',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const errors = {};
Shipments.find({warehouseNo : req.user.unitNo, "packages.status": "In warehouse"})
.then(shipments => {
if (shipments.packages.length === 0) {
errors.nopackages = 'There are no packages for you yet';
return res.status(404).json(errors);
}
res.json(shipments.packages);
})
});
i expect to get something like this
{
"status": "In warehouse",
"date": "2019-09-11T10:19:02.834Z",
"_id": "5d78ca160e47be29e13253b5",
"category": "liquid",
"quantity": "10 pieces",
"description": "garri",
"trackingno": "MHS085533395",
"weight": 123,
"length": 12,
"height": 12,
"width": 13
}
instead i got this
[
{
"status": "Shipped",
"date": "2019-09-11T10:17:46.485Z",
"_id": "5d78c9ca0e47be29e13253b4",
"category": "liquid",
"quantity": "10 pieces",
"description": "garri",
"trackingno": "SDG561920753",
"weight": 123,
"height": 12,
"width": 13
},
{
"status": "In warehouse",
"date": "2019-09-11T10:19:02.834Z",
"_id": "5d78ca160e47be29e13253b5",
"category": "liquid",
"quantity": "10 pieces",
"description": "garri",
"trackingno": "MHS085533395",
"weight": 123,
"length": 12,
"height": 12,
"width": 13
}
]
You should use $elemMatch inside the key packages, i.e. db.getCollection('shipments').find( {warehouseNo: "123"},
{ packages: { $elemMatch: { status: "In warehouse" }}}).
For Example:
I have a collection as below:
{
"_id" : 1.0,
"name" : {
"first" : "John",
"last" : "Backus"
},
"birth" : ISODate("1924-12-03T05:00:00.000Z"),
"death" : ISODate("2007-03-17T04:00:00.000Z"),
"contribs" : [
"Fortran",
"ALGOL",
"Backus-Naur Form",
"FP"
],
"awards" : [
{
"award" : "W.W. McDowell Award",
"year" : 1967.0,
"by" : "IEEE Computer Society"
},
{
"award" : "National Medal of Science",
"year" : 1975.0,
"by" : "National Science Foundation"
},
{
"award" : "Turing Award",
"year" : 1977.0,
"by" : "ACM"
},
{
"award" : "Draper Prize",
"year" : 1993.0,
"by" : "National Academy of Engineering"
}
]
}
Using query like this:
db.getCollection('bios').find( {_id: 1.0 },
{ awards: { $elemMatch: { year: 1967.0 }}})
Gave me a result:
{
"_id" : 1.0,
"awards" : [
{
"award" : "W.W. McDowell Award",
"year" : 1967.0,
"by" : "IEEE Computer Society"
}
]
}
Hope this will help you.
You defined warehouseNo as reference from other table. It must be some ID. Please make sure you are comparing the same

mongo near set maxDistance as value in collection

I am sorry by the title. I was hard to describe. I have this collection
{
"_id" : ObjectId("55cb9c666c522cafdb053a68"),
location: {
type: "Point",
coordinates: [-73.856077, 40.848447]
},
"maxDistancevalue" : 100000
}
Now I want to find of the current location is within: 100000 as defined is the collection by "maxDistancevalue"
The code will be like this. But how set the maxDistancevalue?
db.places.find(
{
location:
{ $near :
{
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$minDistance: **??????, -->maxDistancevalue**
$maxDistance: 0
}
}
}
)
You can use Aggregation Framework's $geoNear pipeline stage to reference other existing field. It requires 2dsphere index to be created on your collection, so start with:
db.places.createIndex({location:"2dsphere"});
and then you can run your aggregate() query:
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
distanceField: "dist.calculated",
maxDistance: "$maxDistancevalue"
}
}
])

How to get the particular field from the couchdb views result using couchdb list function

Below i mentioned the design document.
{
"_id": "_design/link",
"_rev": "62-0c0f00dd9dbedab5c2cca61c356bbff4",
"views": {
"link": {
"map": "function(doc) {\n if (doc.projects) { for (var i in doc.projects) { emit(doc._id, {_id: doc.projects[i].proj_id}); }} \n}"
},
"lists": {
"sample": "function(head, req) {while(row = getRow()){ send(row.doc.proj_name);} }"
}
}
}
The view result:
{
total_rows: 1,
offset: 0,
rows: [
{
id: "SCI130202",
key: "SCI130202",
value: {
_id: "PID00034"
},
doc: {
_id: "PID00034",
_rev: "1-0a363e98a605a72fd71bb4ac62e0b138",
client_id: "E000022",
client_name: "Edinburgh Steel",
type: "manage projects",
proj_id: "PID00034",
proj_name: "Global_upgrade_Oracle",
proj_domain: "Information Technology",
proj_start_date: "2014-10-08",
proj_end_date: "2015-07-07",
delivery_manager: null,
proj_standards: null,
proj_currency_type: "INR",
onsite: "No",
location: "Edinburgh",
proj_status: "Noy yet Start",
budgeted_margin: 45,
budgeted_hrs: 300,
projected_revenue: 200000,
billing_rate: 30,
unit_measure: "per month",
billing_cycle: "Milestone",
proj_core_tech_skills: [ ],
proj_secon_skills: [ ],
proj_sdlc_skills: [ ],
tag: "",
margin: [
{
desired_onsite: null,
desired_offshore: null,
lower_limit: null
}
]
}
}
]
}
I tried but the error comes like
function raised error: (new TypeError("row.doc is undefined", ""))
How to get the proj_name,proj_start_date and proj_end_date using couchdb list function?
You need to add the include_docs=true option to the URL you are using to query the view/list. Views do not automatically include the document.
And maybe you shouldn't use a list to filter your view result - just let the view emit what you need:
emit(doc._id, {
_id: doc.projects[i].proj_id
});
Turns into:
emit(doc.proj_id, {
proj_name: doc.proj_name,
proj_id: doc.proj_id,
proj_start_date: doc.proj_start_date,
proj_end_date: doc.proj_end_date
});
You don't need to emit the doc._id - it is automatically emitted for every row.

Categories

Resources