MongoDB $near query using Java driver - java

I have some shops with products on them in my MongoDB db following this data model:
Shop
{
idShop, name, location {lat, lon}, products [] of int
}
If I run the following command in the mongoDB default console:
db.shops.find({products:1, location:{$near:[41.391204,2.145381]}}).limit(300)
to find the shops that have product nÂș 1 ordered by distance I get the following results:
{ "_id" : ObjectId("4f410cefe4b03a0e3cff6f5a"), "name" : "Shop1", "location" : { "lat" : 41.389915, "lon" : 2.135628 }, "products" : [ 1, 5, 4 ] }
{ "_id" : ObjectId("4f410cefe4b03a0e3cff6f59"), "name" : "Shop2 Center", "location" : { "lat" : 41.388191, "lon" : 2.128816 }, "products" : [ 1, 2, 3 ] }
{ "_id" : ObjectId("4f410cefe4b03a0e3cff6f5c"), "name" : "Shop3", "location" : { "lat" : 41.384712, "lon" : 2.172031 }, "products" : [ 6, 1 ] }
{ "_id" : ObjectId("4f410cefe4b03a0e3cff6f5d"), "name" : "Shop4", "location" : { "lat" : 41.384029, "lon" : 2.173936 }, "products" : [ 6, 1, 2, 3, 4, 5 ] }
Now, I want the same results but using my java servlet. If I search by only product number, the results are OK but not sorted. Then, if I try to sort them by adding a new key/value condition it doesn't return nothing. The code I'm using is the following:
BasicDBObject query = new BasicDBObject();
query.put("products", Integer.parseInt(idProduct));
QueryBuilder query2 = new QueryBuilder();
query2.near(Double.parseDouble(lat), Double.parseDouble(lon));
query.putAll(query2.get());
curShops = collShops.find(query);
This returns an empty JSON. I've also tryed other ways like:
BasicDBObject query = new BasicDBObject();
query.put("products", Integer.parseInt(idProduct));
ArrayList ar = new ArrayList(2);
ar.add(Double.parseDouble(lat));
ar.add(Double.parseDouble(lon));
query.put("location", new BasicDBObject("$near", ar));
curShops = collShops.find(query);
Without any luck.
Can anyone help me with this?
Thanks in advance.

I dont have any experience with java driver, but it seem to me the problem is in this line
query2.near(Double.parseDouble(lat), Double.parseDouble(lon));
Accoridng to mongodb documentation,
The code assumes that you are using decimal degrees in (longitude,
latitude) order. This is the same order used for the GeoJSON spec.
Using (latitude, longitude) will result in very incorrect results, but
is often the ordering used elsewhere, so it is good to double-check
Also from the java mongodb-api-doc, you can see
near
public QueryBuilder near(double x,
double y)
Equivalent of the $near operand
Parameters:
x - x coordinate
y - y coordinate
x-cordinate denotes Longitude here. So the location co-ordinates must be passed as [lon,lat] instead [lat,lon]
Change your query to
query2.near(Double.parseDouble(lon), Double.parseDouble(lat));
to make it work

Yes, this is pretty straight forward. I have just posted an example that should walk you through the solution at http://chuckjohnson.wordpress.com/ - see http://chuckjohnson.wordpress.com/2012/04/02/geospatial-location-based-searches-in-mongodb-part-2-simple-searching/

Related

How to group result of mongodb for following data in the given format

I have data in mongodb in following format. i presented below two row of my mongodb data of table named 'feed'.
{
"_id" : ObjectId("55e80a725ae35bbfc6dce074"),
"sourceId" : "12345",
"sourceName" : "MyPage",
"channelId" : "67890",
"channelName" : "Facebook",
"likeCount" : 1,
"feedData" : {
"from" : {
"id" : "416992615172913",
"name" : "Ashish Kumar"
},
"created_time" : "2015-08-04T09:54:39+0000",
},
"sentiment" : "neutral",
}
{
"_id" : ObjectId("55e80a725ae35bbfc6dce074"),
"sourceId" : "23456",
"sourceName" : "YourPage",
"channelId" : "67890",
"channelName" : "Facebook",
"likeCount" : 2,
"feedData" : {
"from" : {
"id" : "416992615172913",
"name" : "Ashish Kumar"
},
"created_time" : "2015-08-04T09:54:39+0000",
},
"sentiment" : "positive",
}
I want to perform groupBy on field feedData.from.id where channelName is equal to 'Facebook', sum of like count, all sources in an array, all sentiment in an array. i want all data associated with feedData.from.id in the format given below using spring mongo.
{
"feedDatafromid" : "416992615172913",
"name" : "Ashish Kumar",
"sourceName" : ["MyPage","YourPage"],
"channel" : "Facebook",
"likeCount" : 3,
"sentiment" : ["neutral","positive"]
}
Can someone help me to write code in java Spring to group the data of mongodb in given manner.
Suppose we have FeedDbBean class to save the result of aggregation.
Aggregation agg = newAggregation(match(criteria),group(userIdKey).sum("likeCount").as("likeCount").sum("commentCount").as("commentCount").addToSet("sourceName").as("sourceName").addToSet("sourceId").as("sourceId").addToSet("sentiment").as("sentiment").addToSet("channelId").as("channelId").addToSet("channelName").as("channelName").addToSet(userIdKey).as("postUserId").addToSet(userNameKey).as("postUserName"));
results = mongoTemplate.aggregate(agg, FEED_COLLECTION_NAME, FeedDbBean.class);
if(null!=results)
List feedList = results.getMappedResults();
...................
so using given code the result on behalf of userIdKey will be stored in list of FeedDbBean.
each FeedDbBean object will have property like following manner.
feedDbBean.userId = (userId)
feedDbBean.userName = (userName)
feedDbBean.likeCount = (sum of like count group by userId)
feedDbBean.commentCount =(sum of comment count groupby userid)
feedDbBean.sourceName = (all unique source name group by userid show here separated by comma)
feedDbBean.sentiment = (all sentiment separated by comma group by userid)

How to get a a property in a property from a dbobject in java, mongodb

So I have a few dbobjects in my mongo database. Here's an example of one of the objects:
{ "_id" : { "$oid" : "525b048580c3fb0d62d2b6fc"} , "city" : "London" , "currentWeather" : [ { "cloudcover" : "25" , "humidity" : "82" , "observation_time" : "08:37 PM" , "precipMM" : "0.0" , "pressure" : "1008" , "temp_C" : "11" , "temp_F" : "52" , "visibility" : "10" , "weatherCode" : "113" , "weatherDesc" : [ { "value" : "Clear"}] , "weatherIconUrl" : [ { "value" : "http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0008_clear_sky_night.png"}] , "winddir16Point" : "W" , "winddirDegree" : "280" , "windspeedKmph" : "19" , "windspeedMiles" : "12"}]}
Now, I need to get all the dbobjects in my database whose value is lower than a given "temp_C", I have used something like this:
BasicDBObject query = new BasicDBObject("temp_C", new BasicDBObject("&gt", graden));
But it's failing, and I think it is because the property is a subproperty of "currentWeather", yet I have no idea how to address this problem. I am using java to do this.
Looking at your document structure, you're trying to access a subdocument that lives inside an array in your document, so it's a bit more complicated than a standard query:
{ "_id" : { "$oid" : "525b048580c3fb0d62d2b6fc"} , <-- Document
"city" : "London" ,
"currentWeather" : [ <-- Array
{ "cloudcover" : "25", <-- Sub document
...etc...
"pressure" : "1008" ,
"temp_C" : "11",
"temp_F" : "52",
...etc...
}
]
}
In order to get to the nested object, you need to reference its position in the array (in this case, it's zero as it's the first element in the array) and then the field name in the sub document. So your query looks like this:
BasicDBObject query = new BasicDBObject("currentWeather.0.temp_C",
new BasicDBObject("$gt", 11));
Note you had two problems in your original query:
1) You need to reference currentWeather.0.temp_C
2) Your gt operator needs to start with a dollar sign not an ampersand.
Also, you said you wanted the query to return values lower than a given value, in which case you probably want $lt not $gt.
You can't directly use the value of the object of an array in a query. You can use aggregate framework of Mongo. Java Docs For Aggregate are here

Error retrieving using date query in mongodb from Grails gmongo

I have a string as:
'"startDate" : {"\\$gte" : new Date() }'
I actually want to query my mongodb database collection for all the collections with dates after the present date.Here is a sample document:
{
"_id" : ObjectId("51e2a857adc0c2fb535f6904"),
"dateInfo" : {
"dates" : {
"startDate" : ISODate("2013-07-13T04:00:00Z"),
"endDate" : ISODate("2013-07-19T20:00:00Z")
},
"named" : "name1",
"fieldX" : "field1",
"contact" : {
"numbs" : ["+44 121 127 127", "+44 568 789 256", "+44 687 5788 9875"]
}
},
"Locality" : "locality1",
"type" : "ewhet"
}
from mongo shell, I am able to query it as follows:
db.collectionName.find({"dateInfo.dates.startDate" : {"$gte" : new Date()}})
Now I want to do it from groovy. I am trying to do it as(using mongoDB java api):
DBCursor cursor = db.collectionName.find(new JsonSlurper().parseText('{"startDate" : {"\$gte" : new Date() }}'))
Above code gives error as:
Lexing failed on line: 1, column: 48, while reading 'new ', was trying to match the constant 'null'
Now the problem with JsonSlurper is that it requires double quotes in both key and value names.But in case I put a double quote in new Date(), it wont be evaluated by mongodb.
So what can be done here?
Have you tried:
db.collectionName.find( [ 'dateInfo.dates.startDate' : ['$gte' : new Date() ] ] )

mongodb geoSpatial query doesn't work

I'm trying to fetch records within a specific radius in km/miles.
mongodb 2d index:
db.collection.ensureIndex({locaction:"2d"})
a record in the collection has the indexed key:
"location" : { "longitude" : 34.791592164168, "latitude" : 32.0516908 0405 }
Calling collection's getIndexes() from shell gives me this:
...{
"v" : 1,
"key" : {
"location" : "2d"
},
"ns" : "events.events",
"name" : "location_2d"
}...
despite all the above, trying to fetch records with this command fails:
> db.events.find({location:{ $near :{ longitude:34,latitude:32},$maxDistance:10 / 3963.192}})
anyone can point out what prevent this from working?
AFAIK, $near takes an array of the two target values, so you can try giving your values in array: -
db.events.find({location:{ $near : [34, 32],$maxDistance:10 / 3963.192}})

Update data with mongoDB in Java

I have a little bug with my script:
BasicDBObject change = new BasicDBObject();
BasicDBObject account =
new BasicDBObject().append("$set", new BasicDBObject().append("status", 0));
account.append("pos.X", getX());
account.append("pos.Y", getY());
account.append("pos.Z", getZ());
change.append("pseudo", gPlayer);
coll.update(change, account);
And the structure of mongoDB is :
{
pseudo: "pseudo"
email: "email"
password: "password"
status: "1"
pos: [
{X: "90.45}
{Y: "90.45}
{Z: "90.45}
]
}
But this is not working! No value is modified.
Thanks for your help.
Java is a very verbose language, and sometimes it is easiest to first write your query using the JS shell, make sure it performs as desired, and then translate it into Java.
By adding System.out.println(account.toString()) to your Java code, I can see that your Update document looks like the following, which is not valid:
{ "$set" : { "status" : 0} , "pos.X" : "90.45" , "pos.Y" : "90.45" , "pos.Z" : "90.45"}
From your question, it is not entirely clear what you would like your updated document to look like, but I am guessing that you would like to modify the values of "status" and "pos.0.X", "pos.1.Y", and "pos.2.Z". Because X, Y, and Z are all stored as individual embedded documents inside an array, they will have to be referenced by their positions in order to be updated at the same time. If possible, you might find it preferable to rearrange your document structure such that X, Y, and Z are all stored inside the same document, like so:
"pos" : {
"X" : "0",
"Y" : "0",
"Z" : "0"
}
This way, you will be able to access each variable more easily using dot notation, pos.X, pos.Y, pos.Z, which from your post looks like what you were intending. More information on embedded documents may be found in the "Dot Notation (Reaching into Objects)" documentation:
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
Here is an Update statement that will modify the above values:
> db.pseudo.find({ "pseudo" : "gPlayer"}).pretty()
{
"_id" : ObjectId("4f904ebb5bebd4375b759c90"),
"email" : "email",
"password" : "password",
"pos" : [
{
"X" : "90.45"
},
{
"Y" : "90.45"
},
{
"Z" : "90.45"
}
],
"pseudo" : "gPlayer",
"status" : "1"
}
> db.pseudo.update({"pseudo" : "gPlayer"}, { "$set" : { "status" : 0 , "pos.0.X" : "0" , "pos.1.Y" : "0" , "pos.2.Z" : "0"}})
> db.pseudo.find({ "pseudo" : "gPlayer"}).pretty()
{
"_id" : ObjectId("4f904ebb5bebd4375b759c90"),
"email" : "email",
"password" : "password",
"pos" : [
{
"X" : "0"
},
{
"Y" : "0"
},
{
"Z" : "0"
}
],
"pseudo" : "gPlayer",
"status" : 0
}
>
Translated into Java this is:
BasicDBObject change = new BasicDBObject("pseudo", "gPlayer");
BasicDBObject setDoc = new BasicDBObject();
setDoc.append("status", "0");
setDoc.append("pos.0.X", "0");
setDoc.append("pos.1.Y", "0");
setDoc.append("pos.2.Z", "0");
BasicDBObject account = new BasicDBObject("$set", setDoc);
coll.update(change, account);
I realize that I guessed a little bit about exactly the update that you would like to do, but hopefully the above will get you pointed in the right direction!

Categories

Resources