My MongoDB json structure is
{
"_id" : "122134231234234",
"name" : "Total_pop",
"description" : "sales category",
"source" : "public",
"dataset" :"d1"
},
{
"_id" : "1123421231234234",
"name" : "Total_pop",
"description" : "sales category",
"source" : "public",
"dataset" :"d1"
},
{
"_id" : "12312342332423343",
"name" : "Total_pop",
"description" : "sales category",
"source" : "private",
"description" : "d1"
}
I need to get collection distinct of dataset where source is public.
I tried this query, and it didn't work:
Criteria criteria = new Criteria();
criteria.where("source").in("public");
query.addCriteria(criteria);
query.fields().include("name");
query.fields().include("description");
query.fields().include("description");
query.fields().include("source"); List list =
mongoTemplate.getCollection("collectionname").distinct("source", query);
Can you please help me out?
For one thing the .getCollection() method returns the basic Driver collection object like so:
DBCollection collection = mongoTemplate.getCollection("collectionName");
So the type of query object might be different from what you are using, but there are also some other things. Namely that .distinct() only returns the "distint" values of the key that you asked for, and doe not return other fields of the document. So you could do:
Criteria criteria = new Criteria();
criteria.where("dataset").is("d1");
Query query = new Query();
query.addCriteria(criteria);
List list = mongoTemplate.getCollection("collectionName")
.distinct("source",query.getQueryObject());
But that is only going to return "sample" as a single element in the list for instance.
If you want the "fields" from a distinct set then use the .aggregate() method instead. With either the "first" occurances of the other field values for the distinct key:
DBCollection colllection = mongoTemplate.getCollection("collectionName");
List<DBObject> pipeline = Arrays.<DBObject>asList(
new BasicDBObject("$match",new BasicDBObject("dataset","d1")),
new BasicDBObject("$group",
new BasicDBObject("_id","$source")
.append("name",new BasicDBObject("$first","$name"))
.append("description", new BasicDBObject("$first","$description"))
)
);
AggregationOutput output = colllection.aggregate(pipeline);
Or the actual "distinct" values of multiple fields, by making them all part of the grouping key:
DBCollection colllection = mongoTemplate.getCollection("collectionName");
List<DBObject> pipeline = Arrays.<DBObject>asList(
new BasicDBObject("$match",new BasicDBObject("dataset","d1")),
new BasicDBObject("$group",
new BasicDBObject("_id",
new BasicDBObject("source","$source")
.append("name","$name")
.append("description","$description")
)
)
);
AggregationOutput output = colllection.aggregate(pipeline);
There are also a direct .aggregate() method on mongoTemplate instances already, which has a number of helper methods to build pipelines. But this should point you in the right direction at least.
As of Spring Data Mongo 2.2.0 MongoTemplate provides a function to retrieve the distinct field with criteria,
Criteria criteria = new Criteria("country").is("IN");
Query query = new Query();
query.addCriteria(criteria);
return mongoTemplate.findDistinct(query,"city",Address.class,String.class);
Which basically finds all the distinct cities in address collection where country is IN.
Related
I think this should be easy to do, but I just couldn't figure it out.
What I'm trying to achieve is this query
{inbox:{$in:["main","fun-inbox"]} ,status:"Open"}
I managed to make it work like this
Bson q = Filters
.and(Filters
.in("inbox", inboxes),
Filters
.eq("status", statusID));
but is not the same thing because I used the $and operator
Can this be done using Document ?
Here is what I've tried and I know is wrong the way I define it, but I'll put the example just to better understand what I'm trying to achieve
Document q1 = new Document()
.append("inbox", Filters.in("inbox", inboxes))
.append("status", statusID);
What you have is correct and it is not explicitly $anded.
Java Mongo driver behind the scene figures out when to $and and when to not.
For example
Without $and
Bson bson = Filters.and(Filters.in("inbox", inboxes), Filters.eq("status", status));
BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry());
System.out.print(bsonDocument.toString()); //{ "inbox" : { "$in" : inboxes }, "status" : status }
With $and
Bson bson = Filters.and(Filters.in("inbox", inboxes), Filters.eq("inbox", inbox));
BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry());
System.out.print(bsonDocument.toString()); //{ "$and" : [{ "inbox" : { "$in" : inboxes } }, { "inbox" : inbox }] }
Converted your query to java code to return Iterable Document type
FindIterable<Document> iterable = database.getCollection("mails").find(new Document("inbox", new Document("$in", inValues)).append("status", "open"));
and inValues is an ArrayList as
ArrayList<String> inValues = new ArrayList<String> ();
inValues.add("main");
inValues.add("fun-inbox");
Could someone please tell me how to set a map as a value for an attribute that does not yet exist. I've been trying an update expression "SET MyAttr.#key = :val", but that only works if the attribute exists and if the value of the attribute is already a map.
I tried using "ADD MyAttr.#key = :val" instead, but then I get:
Invalid UpdateExpression: Syntax error; token: "=", near: "#key = :val"
I'm using Java. Note that I'm using an attempting an UpdateItem request to do this. It just occurred to me that maybe this doesn't work with maps. I just assumed it would because I've always been able to have a new item and/or attribute created with an update request if doesn't already exist (with other attribute value data types like string, number etc).
Let's assume that we have the following Item in our DynamoDB Table:
{
"id": "91c2b60d-c428-403c-be42-8657b4f20669",
"firstName": "John",
"lastName": "Doe"
}
and we want to add custom attributes that we have in a Map:
Map<String, String> customAttributes = new HashMap<>();
customAttributes.put("age", "21");
customAttributes.put("gender", "Male");
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamodb = new DynamoDB(client);
Table table = dynamodb.getTable("users");
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("id", "91c2b60d-c428-403c-be42-8657b4f20669")
.withUpdateExpression("set #customAttributes = :customAttributes")
.withNameMap(new NameMap().with("#customAttributes", "customAttributes"))
.withValueMap(new ValueMap().withMap(":customAttributes", customAttributes))
.withReturnValues(ReturnValue.ALL_NEW);
UpdateItemOutcome outcome = table.updateItem(updateItemSpec);
System.out.println(outcome.getItem().toJSONPretty());
The result:
{
"id" : "91c2b60d-c428-403c-be42-8657b4f20669",
"firstName" : "John",
"lastName" : "Doe",
"customAttributes" : {
"gender" : "Male",
"age" : "21"
}
}
Now, if we want to add a new attribute to the customAttributes map:
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("id", "91c2b60d-c428-403c-be42-8657b4f20669")
.withUpdateExpression("set customAttributes.#occupation = :value")
.withNameMap(new NameMap().with("#occupation", "occupation"))
.withValueMap(new ValueMap().withString(":value", "Programmer"))
.withReturnValues(ReturnValue.ALL_NEW);
UpdateItemOutcome outcome = table.updateItem(updateItemSpec);
System.out.println(outcome.getItem().toJSONPretty());
I suggest that you take a look at: DynamoDBMapper, it will save you tons of lines of code.
I am working with MongoDB v3.0.1 and the MongoDB Java Driver 3.0.0-RC1.
I have an user collection with fields like "username", "firstname", "lastname", "email", and so on.
Now I want to select all users but only with the fields "username", "firstname" and "lastname".
On the Mongo-Shell it is working with db.user.find({}, { "username" : true , "firstname" : true , "lastname" : true})
But how can I do it in Java? I tried it with
final BasicDBObject query = new BasicDBObject("{}", new BasicDBObject("_id", true));
final MongoCursor<Document> usersCursor = col.find(query)
For this I get an empty result back because it's translated as { "{}" : { "_id" : true , "firstname" : true , "lastname" : true}}.
I also tried it with BasicDBList, but this isn't accepted by col.find()
With the "old" Mongo 2.x driver I would use new BasicDBObject(BasicDBObject(), new BasicDBObject("username", true).append("firstname", true).append("lastname", true)
Is there a possibility to do that or do I have to fetch all fields?
Greetings
Sören
With the new CRUD API in the 3.0.0 Java driver, the proper way to do it is with the projection method that is chained off off MongoCollection.find(). Since the projection method takes an instance of the Bson interface, there are a number of different classes you can use to specify the projection:
// using BasicDBObject
collection.find().projection(new BasicDBObject("username", true)
.append("lastname", true)
.append("firstname", true))
// using the new Document class
collection.find().projection(new Document("username", true)
.append("lastname", true)
.append("firstname", true));
// Using the new Projections builder
collection.find().projection(Projections.include("username", "lastname", "firstname"));
As for the way you say it works in the 2.x driver, that's not possible, as
new BasicDBObject(BasicDBObject(), BasicDBObject("username", true)
.append("firstname", true)
.append("lastname", true)
does not compile. I'm not sure what exactly you were doing with 2.x, but the proper way to accomplish this with the DBCollection class in 2.x (which is still supported in the 3.0 driver), is:
collection.find(new BasicDBObject(), new BasicDBObject("username", true)
.append("lastname", true)
.append("firstname", true));
Have a look at the implementation of DBCollection find(). The following returns the "username", "firstname", "lastname" and "_id" fields for every document in the collection that has an "username", "firstname" and "lastname" fields:
BasicDBObject keys = new BasicDBObject();
keys.put("username", 1);
keys.put("firstname", 1);
keys.put("lastname", 1);
final MongoCursor<Document> usersCursor = col.find(new BasicDBObject(), keys);
collection
.find(new Document(...).append(...))
.projection(new Document(...).append(...))
This will give you a FindIterable and then you can iterate through as you would DBCursor.
I have to aggregate some data in mongodb through the java driver, and save the aggregation result in a new collection, and later print this collection in a Jtable; the id field can be not simple in my case (i can't know if it is a single value or not) so I followed this:
How to write multiple group by id fields in Mongodb java driver
when I want to save the result in a new collection, doing this:
for (DBObject result : output.results()) {
report.insert(result);
}
i have this error:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: fields stored in the db can't have . in them. (Bad Key: 'store.address.store_state')
this is a piece of the collection where I do the aggregation:
{
"_id" : ObjectId("549ef5d17c8db9efa75d49c9"),
"store" : {
"store_id" : NumberLong(2),
"store_type" : "Small Grocery",
"region_id" : NumberLong(78),
"store_name" : "Store 2",
"store_number" : NumberLong(2),
"address" : {
"store_street_address" : "5203 Catanzaro Way",
"store_city" : "Bellingham",
"store_state" : "WA",
"store_postal_code" : "55555",
"store_country" : "USA",
"store_manager" : "Smith"
},
.....}
Can anyone help me?
Note: ID Field can be simple (only a field) or complex (two or more fields)
The new collection I want to create must have all the fields that compose the ID in the aggregation, and all the fields result by aggregation. That's beacause I had to print that collection in this way: Retrieve data from MongoDB collection into Swing JTable
for example:
DBObject fields = new BasicDBObject("unit_sales", 1);
fields.put("store.store_type", 1);
fields.put("store.store_name", 1);
fields.put("store.address.store_city", 1);
fields.put("_id", 0);
DBObject project = new BasicDBObject("$project", fields );
Map<String, Object> dbObjIdMap = new HashMap<String, Object>();
dbObjIdMap.put("store_type", "$store.store_type");
dbObjIdMap.put("store_name", "$store.store_name");
dbObjIdMap.put("store_city", "$store.address.store_city");
DBObject groupFields = new BasicDBObject( "_id", dbObjIdMap);
groupFields.put("average", new BasicDBObject("$avg", "$unit_sales"));
DBObject group = new BasicDBObject("$group", groupFields);
AggregationOutput output = collection.aggregate(project, group);
So i want as result a table with column store_type,store_name, store_city, average.
I know I'm exposing my problem here so bad, but i'm not english and i don't speak very well the language, so please try to understand me.. sorry
I need two to add new items to the existing data in mongo db.
This is mongo db I have the following data.
{
"_id" : ObjectId("53ce11e7d0881d32d9fa935f"),
"name" : "massive riots",
"lastFeachedTime" : "Jul 15, 2014 12:55:27 PM"
}
Here I have to find the data based on name and the I have to add another two items two it.
Here is my code.
DBObject queryObject = new BasicDBObject().append("name", keyword);
if (null == newFetchTime) {
}
DBObject updateObject = new BasicDBObject();
updateObject.put("nextPageToken", nextPageToken);
updateObject.put("prevPageToken", prevPageToken);
Utils utils = new Utils();
DBCollection collection = utils.getStaging().getCollection("test");
collection.update(queryObject, updateObject, true, false);
But I am do update the existing value get removed and the new data get added.
Can any one tell me how to add the items to the existing data in mongo db.
You want the $set operator in your update. This allows the specified fields to be altered without affecting any of the existing fields in the document, unless the specified field exists in which case that field is overwritten:
DBObject update = new BasicDBObject(
"$set", new BasicDBObject()
.append("nextPageToken",nextPageToken)
.append("prevPageToken",prevPageToken)
);
Works out to the equivalent in shell:
{ "$set" : { "nextPageToken" : nextPageToken , "prevPageToken" : prevPageToken }}