I want to apply criteria inside object of array if it matches, but I am not able to find any documentation or example where I can find that using spring-data-cosmosdb library. I am using 2.3.0 version of library.
Example of Json
{
"id" : 1,
"address" : [
{
"street" : "abc"
...
},
{
"street" : "efg"
...
}
]
}
I wan to search all documents in which address is having street name equals "abc". Below is spring boot code that I am using to search in cosmosDb. But it is not returning expected results.
List<Criteria> criteriaList = new ArrayList<>();
criteriaList.add(Criteria.getInstance(CriteriaType.IN, "addresses.street", Collections.singletonList("abc")));
List<User> users = cosmosTemplate.find(new DocumentQuery(criteriaList.get(0), CriteriaType.AND)), User.class, COLLECTION_NAME);
I also tried with address[0].street, but it is throwing exception of operation not supported.
Strongly recommend upgrading to spring-data-cosmosdb v3 (at least version 3.22.0). The v2 connector has been legacy for some time. Using the latest connector, the below would accomplish your goal.
Criteria filterCriteria = Criteria.getInstance(CriteriaType.ARRAY_CONTAINS, "address",
Collections.singletonList(new ObjectMapper().readTree("{\"street\":\"abc\"}")),
Part.IgnoreCaseType.NEVER);
CosmosQuery cosmosQuery = new CosmosQuery(filterCriteria);
Iterable<User> results = cosmosTemplate.find(cosmosQuery, User.class, COLLECTION_NAME);
for (User user : results)
System.out.println("doc id: " + user.getId());
Related
I'm trying to get the order number where a transactionId is equal to another variable I have in my code. My tolls.booths collection looks like this
In my code,
def boothsException = booths.find([ "pings.loc.transactionId": tollEvent.id, "pings.loc.order":1] as BasicDBObject).iterator()
println boothsException
I am getting boothsException = DBCursor{collection=DBCollection{database=DB{name='tolls'}
I would like to essentially say get where transactionId = 410527376 and give me that order number in boothsException (5233423).
This is using MongoDB Java Driver v3.12.2.
The code extracts the value from the returned cursor. I am using newer APIs, so you will find some differences in class names.
int transId = 410527376; // same as tollEvent.id
MongoCursor<Document> cursor = collection
.find(eq("pings.loc.transactionId", transId))
.projection(fields(elemMatch("pings.loc.transactionId"), excludeId()))
.iterator();
while (cursor.hasNext()) {
Document doc = cursor.next();
List<Document> pings = doc.get("pings", List.class);
Integer order = pings.get(0).getEmbedded(Arrays.asList("loc","order"), Double.class).intValue();
System.out.println(order.toString()); // prints 5233423
}
NOTES:
The query with projection gets the following one sub-document from the pings array:
"pings" : [
{
"upvote" : 575,
"loc" : {
"type" : "2dsphere",
"coordinates" : [ .... ],
"transactionId" : 410527376,
"order" : 5233423
},
...
}
]
The remaining code with looping the cursor is to extract the order value from it.
The following are the imports used with the find method's filter and projection:
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Projections.*;
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");
Here is the sample document of my MongoDB:
user:{
_id:1,
name:'xyz',
age:12,
mobile:21321312,
transaction:[{
trans_id:1,
prod:'a',
purchasedAt:ISODate("2015-02-01"),
},
{
trans_id:2,
prod:'b',
purchasedAt:ISODate("2015-02-01")
},
{
trans_id:3,
prod:'c',
purchasedAt:ISODate("2014-11-24")
}]
,...
}
My query looks like:
db.user.find({transaction:{$elemMatch:{prod:'a', purchasedAt:ISODate("2015-02-01")}}, transaction:{$elemMatch:{prod:{$nin:['b','c']}, purchasedAt:ISODate("2015-02-01")}}}).count()
I am trying to get the user count who have purchased product 'a' on date "2015-02-01" but not have purchased product b & c on same day.
So while trying to do this in Java with the query:
coll.find(new BasicDBObject().append("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", 'a').append("purchasedAt", Date))).append("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", new BasicDBObject("$nin",['b','c'])).append("purchasedAt", Date)));
I have also tried:
coll.find(new BasicDBObject("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", 'a').append("purchasedAt", Date))).append("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", new BasicDBObject("$nin",['b','c'])).append("purchasedAt", Date)));
where Date is "2015-02-01" in util.Date object.
I found out that Java ignores the $in part of the query, i.e. it ignores {transaction:{$elemMatch:{prod:'a', purchasedAt:ISODate("2015-02-01")}} & performs only $nin part.
I found out it by DBCursor object.
Here's the output of the cursor:
Cursor: Cursor id=0, ns=mydb.user, query={ "transaction" : { "$elemMatch" : { "prod" : { "$nin" : [ "b" , "c"]} , "purchasedAt" : { "$date" : "2015-02-01T00:00:00.000Z"}}}}, numIterated=0, readPreference=primary
Because of this my result is inaccurate. I wonder why the exact same query works well in Mongo shell but doesn't with Java API. Is there anything wrong with my query structure?
My guess is that this question is now moot, but, if you still do not consider it answered, are you looking for the "$not" operator, which can check for non-existance sort of.
I have the following code, :
CommandResult cr = db.doEval("db." + collectionName + ".aggregate("
+ query + ")");
Command result is giving in batches, where I need to get in single value.
Batch Result:{ "serverUsed" : "/servername" , "retval" : { **"_firstBatch**" : [ { "visitor_localdate" : 1367260200} , { "visitor_localdate"
Expected Result:
{ "serverUsed" : "/servername" , "retval" : { "**result**" : [ { "visitor_localdate" : 1367260200} , { "visitor_localdate"
The Mongo DB we are using is 2.6.4 with 64 bit.
Can any one help with this?. I am guessing there is some Configuration issue.
Your doing this all wrong. You don't need to jump through hoops like this just to get a dynamic collection name. Just use this syntax instead:
var collectionName = "collection";
var cursor = db[collectionName].aggregate( pipeline )
Where pipeline also is just the array of pipeline stage documents, ie:
var pipeline = [{ "$match": { } }, { "$group": { "_id": "$field" } }];
At any rate the .aggregate() method returns a cursor, you can iterate the results with standard methods:
while ( cursor.hasNext() ) {
var doc = cursor.next();
// do something with doc
}
But you are actually doing this in Java and not JavaScript, so from the base driver with a connection on object db you just do this:
DBObject match = new BasicDBObject("$match", new BasicDBObject());
DBObject group = new BasicDBObject("$group", new BasicDBObject());
List pipeline = new ArrayList();
pipeline.add(match);
pipeline.add(group);
AggregationOutput output = db.getCollection("collectionName").aggregate(pipeline);
The pipeline is basically a list interface of DBObject information where you construct the BSON documents representing the operations required.
The result here is of AggregationOutput, but cursor like results are obtainable by additionally supplying AggregationOptions as an additional option to pipeline
There was something related to bacth added in mongodb 2.6, more details here: http://docs.mongodb.org/manual/reference/method/db.collection.aggregate/#example-aggregate-method-initial-batch-size
From the link
db.orders.aggregate(
[
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 2 }
],
{
cursor: { batchSize: 0 }
}
)
You might be having a cursor batch in your aggregate query
The answer from Neil Lunn is not wrong but I want to add that the result you were expecting is a result for mongodb versions earlier than v2.6.
Before v2.6, the aggregate function returned just one document containing a result field, which holds an array of documents returned by the pipeline, and an ok field, which holds the value 1, indicating success.
However, from mongodb v2.6 on, the aggregate function returns a cursor (if $out option was not used).
See examples in mongodb v2.6 documentation and compare how it worked before v2.6 (i.e. in v2.4):
Below is the JSON file from which I want to retrieve the phone number:
"_data" : {
"Variable key" : {
"Name" : "Hello World",
"Phone" : "Phone : 123-456-6789 ",
"Region" : "New York",
"Description" : ""
}
}
My Java Code is:
BasicDBObject query = new BasicDBObject();
BasicDBObject field = new BasicDBObject();
field.put("_data.Phone", 1);
DBCursor cursor = table.find(query,field);
String str;
while (cursor.hasNext()) {
BasicDBObject obj = (BasicDBObject) cursor.next();
str=cursor.curr().get("_data.Phone").toString();
System.out.println(str);
}
which will return null as I'm not considering the variable key.
My problem is there are many JSON files present in the mongo database each having different "Variable Key" and this key may change after sometime. As this key may change over time, how can I retrieve the phone number ?
Thank You !!
Which phone numbers do you want? Your query will return all documents and you are trying to project out just the phone number, but with an incorrect projection specification. If you want all phone numbers, just leave out the projection specification entirely or project on { "_data" : 1 }. If you want the phone numbers associated with specific variable keys, project those out using dot notation like { "_data.key_name.Phone" : 1 }. If you don't know the names of the keys that you want to project on, then that is your root problem that you need to solve before you ask MongoDB to return something that you don't know that you want (or that you don't want).