I am getting a String with the structure of JSONArray [ { "abc" : "123" }, { "def" : "456" } ]which I need to use to call mongoCollection.aggregate(theString);
The aggregate function takes List<? extends Bson> and I am not sure what is the best way to convert the String to List<? extends Bson>.
For find() method which takes Bson var1 I am just converting the String to Document using Document.parse(theString);
I am using mongodb 3.4.
I was able to come up with this but it looks a little ugly.
JSONArray array = new JSONArray(theString);
List<Document> list = new ArrayList<>();
for(Object jsonObject : jsonArray){
Document document = Document.parse(jsonObject.toString());
list.add(document);
}
collection.aggregate(list);
Related
I am trying to use the following find query,
{
"uid" : { "$in" : ["value1", "value2"] }
}
The array ["value1", "value2"] should be set dynamically from Scala Array[String].
Here is my code,
def find(uids: Array[String]): Future[Seq[User]] = {
val query: JsObject = Json.parse(JsonUtil.toInQuery(uids, "uid")).asInstanceOf[JsObject]
collection.flatMap(_.find(query)
.cursor[User](ReadPreference.primary)
.collect[Seq]()
)
}
The method JsonUtil.toInQuery(uids, "uid") is creating the json string of the query. I have tried using BSONDocument and writing Json query manually instead of passing json string, but it does not seem to work.
Can anyone suggest me a working way to use that query in reactive-mongo with play framework 2.6 ?
Update
public static String toJsonString(String[] arr){
return Json.toJson(arr).toString();
}
public static String toInQuery(String[] arr, String item){
return "{ \""+item+"\": {\"$in\": "+toJsonString(arr)+"}}";
}
I got it working. But, not sure if this is the correct approach.
How to identify the number of elements in the particular embedded document (or) how to find the number of elements in the embedded array?
Award
{
"brand" : [
{
"name" : "multi",
"descr" : "Multpple"
},
{
"name" : "multi",
"descr" : "two"
},
{
"name" : "multi",
"descr" : "three"
}
],
"name" : "Test",
"narname" : "Nar"
}
For Eg: In the above document how to find the number of elements that is inside the embedded array BRAND using Spring Data.?
Any pointers would be greatly appreciated !
I don't think there is a method which can get the answer directly.
You can use aggregate to implement it. For example, if you want to get the count of elements in array brand in a specific document, this way should be available (run on mongo shell):
db.Award.aggregate({$match:{_id:id}}, {$unwind:"$brand"}, {$group:{_id:"$_id", count:{$sum:1}}});
count is the result you want.
Then implement that using spring-data-mongodb syntax.
-------------- APPENDED ---------------------
// You can find the relative aggregation method from MongoTemplate.java file to handle your requirements.
// For exmaple:
// public <O> AggregationResults<O> aggregate(Aggregation aggregation, Class<?> inputType, Class<O> outputType)
// The version is around spring-data-mongodb-1.5.0 or higher.
// Below I call the mongo-java-driver directly because I find it needs some time to learn it from spring-data-mongodb. :)
protected int getArraySize(Object id, String collName) {
// Attention: make sure id is in the correct data type because the following statement would not convert it automatically.
// Issue codes according to this command line:
// db.Award.aggregate({$match:{_id:id}}, {$unwind:"$brand"}, {$group:{_id:"$_id", count:{$sum:1}}});
DBObject match = BasicDBObjectBuilder.start().push("$match").append("_id", id).get();
DBObject unwind = new BasicDBObject("$unwind", "$brand");
DBObject group = BasicDBObjectBuilder.start().push("$group").append("_id", "$_id").push("count").append("$sum", 1).get();
List<DBObject> pipeline = Arrays.asList(match, unwind, group);
// This aggregate method is supported in higher version of mongo-java-driver, here I use is 2.12.3
AggregationOutput aggr = this.mongoTemplate.getCollection(collName).aggregate(pipeline);
for (DBObject dbo : aggr.results()) {
Object count = dbo.get("count");
if (count instanceof Number) {
return ((Number)count).intValue();
}
}
return 0;
}
I am trying to build an $in query with QueryBuilder (MongoDB Java API 2.9.1). I have no problem when the query is an array of strings but when I try with an array of ObjectIds it doesn't work (returns nothing).
I am able to run the query successfully and get a result from the console:
Query in console:
db.collection.find({removed:false,app_id: {$in : [ObjectId("4f75c533ac99d845186e19b2"), ObjectId("4f75c533ac99d845186e19b3")]}})
Query created by QueryBuilder (MongoDB Java API 2.9.1):
Object[] ids;
Java code:
DBObject query = QueryBuilder.start("app_id").in(ids).and("removed").is(false).get();
ToString on DBObject produces:
{ "app_id" : { "$in" : [ { "$oid" : "4f75c533ac99d845186e19b2"}]} , "removed" : false}
Not sure if I am doing something wrong or the API doesn't support and $in query of type ObjectId. Any ideas?
Your ids should be of type org.bson.types.ObjectId so something like this should work:
import org.bson.types.ObjectId;
ObjectId[] ids = new ObjectId[]{
new ObjectId("1234568abcd"),
new ObjectId("1234567abcd")};
DBObject query = QueryBuilder.start("app_id").in(ids)
.and("removed").is(false).get();
I recently spent some time trying to use the $pull operator through Spring's Data MongoOperations interface, so I thought it would be nice to share my findings in case anyone bumps into a similar problem.
So here it goes...
I have 2 java POJOs like so :
#Document
public class OutterObject{
private String id;
private String name;
private List<InnerDocument> innerDocs;
//SETTERS - GETTERS Ommited
public class InnerDocument{
private String id;
private String name;
//SETTERS - GETTERS Ommited
This is stored in a Mongo collection like so :
"_id" : "doc2",
"_class" : "OutterObject",
"name" : "doc2",
"innerDocs" : [{
"_id" : "innerDoc21",
"name" : "innerDoc21"
}, {
"_id" : "innerDoc22",
"name" : "innerDoc22"
}]
I'm trying to use the $pull operator in order to remove all objects inside the innerDoc collection having a name value = "innerDoc22".
I know how to accomplish this using the mongo driver like so :
List<String> ids =
Arrays.asList("innerDoc22");
BasicDBObject find = new BasicDBObject();
match.put("innerDocs.name",
BasicDBObjectBuilder.start("$in", ids).get());
BasicDBObject update = new BasicDBObject();
update.put(
"$pull",
BasicDBObjectBuilder.start("innerDocs",
BasicDBObjectBuilder.start("name", "innerDoc22").get()).get());
DBCollection col= mongoOperations.getDb().getCollection("outterObject");
col.update(find , update);
I'm trying to accomplish the same thing using Spring's MongoOperations Interface.
Here is my code using the MongoOperations interface :
List<String> ids = Arrays.asList("innerDoc22");
Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));
WriteResult wc = mongoOperations.upsert(
removeQuery,
new Update().pull("innerDocs.name", "innerDoc22"),
OutterObject.class);
System.out.println(wc.getLastError());
I'm not getting any errors when calling getLastError() the update is simply not done in the database.
I know a similar question has already been asked here but the answer that was given does not use the MongoOperations interface.
After searching a bit and looking at the source code I realized that I needed to pass an InnerDocument object as a second parameter to the pull method so that the spring classes would be able to do the mapping correctly.
As it turns out I can navigate objects while selecting objects (I'm using "innerDocs.name" in the removeQuery) but I cannot (or havent found a way) do the same when updating a document.
Below is how I implemented the query using MongoOperations :
List<String> ids = Arrays.asList("innerDoc22", "innerDoc21");
Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));
WriteResult wc =
mongoOperations.upsert(removeQuery,
new Update().pull("innerDocs",
new InnerDocument("innerDoc22", null)),
OutterObject.class);
System.out.println(wc.getLastError());
You can also use the BasicDBObject instead of the InnerDocument I found this out by accident. By printing out the update object, you can see the actual mongo shell query json, which is super helpful for debugging.
:
Update updateObj = new Update()
.pull("innerDocs", new BasicDBObject("innerDocs.name","innerDoc22"));
System.out.println("UPDATE OBJ: " + updateObj.toString());
results in:
UPDATE OBJ: { "$pull" : { "innerDocs" : { "innerDocs.name" : "innerDoc22"}}}
I tried the solution given by med116 and I had to modify it to work :
Update updateObj = new Update().pull("innerDocs", new BasicDBObject("name","innerDoc22"));
Because otherwise there was no matching object in my array.
in spring data mongo,just like this:
//remove array's one elem
UpdateResult wc = mongoTemplate.upsert(removeQuery,new Update().pull("tags",Query.query(Criteria.where("tag").is("java"))),TestPull.class);
//remove array's multi-elem
UpdateResult wc1 = mongoTemplate.upsert(removeQuery,new Update().pull("tags",Query.query(Criteria.where("tag").in(Arrays.asList("mongo", "netty")))),TestPull.class);
If you simply want to remove an element from array which does not have any other property like name then write the query you wish and
Update update = new Update();
update.pull("Yourarrayname","valueyouwishtodelete");
mongoTemplate.upsert(query,update,"collectionname");
That's my solution - thanks to #ufasoli:
public Mono<ProjectChild> DeleteCritTemplChild(String id, String idch) {
Query query = new Query();
query.addCriteria(Criteria
.where("_id")
.is(id)
.and("tasks._id")
.is(idch)
);
Update update = new Update();
update.set("tasks.$", null);
return template
// findAndModify:
// Find/modify/get the "new object" from a single operation.
.findAndModify(
query, update,
new FindAndModifyOptions().returnNew(true), ProjectChild.class
);
}
This works for me!
UpdateResult updateResult = mongoTemplate.updateMulti(new Query(where("id").is(activity.getId())), new Update().pull("comments", new Query(where("id").is(commentId))), Activity.class);
It will generate:
Calling update using query: { "_id" : { "$oid" : "61f900e7c7b79442eb3855ea"}} and update: { "$pull" : { "comments" : { "_id" : "61fac32e3f9ab5646e016bc8"}}} in collection: activity
I have to write a complex mongo query using java but am not able to do it.
The mongo query looks like this:
db.video.findOne( {
$or: [
{ key1: { $in : [764] } },
{ key2: {$in : [list2] } },
{ $and [ { key2 : 3}, {key4:67} ] }
]
})
I have to write the above query using the QueryBuilder class. In what way can I do it?
Thanks
Using QueryBuilder your query should look like this
DBObject query = QueryBuilder.start().or(
QueryBuilder.start("key1").in(764).get(),
QueryBuilder.start("key2").in(keys).get(),
QueryBuilder.start().and("key3").is(3).and("key4").is(64).get()
).get();
Consider using jongo (an API over mongo-java-driver) you can simply copy/paste queries from the shell :
collection.findOne("{$or:[{key1: {$in:[764]}},{key2:{$in:[#]}}, {$and:[{key3:3},{key4:67}]}]}", keys).as(People.class);
I had the same problem and i got a solution in another way :
ArrayList orList = new ArrayList();
ArrayList andList = new ArrayList();
orList.add(new BasicDBObject("key1", new BasicDBObject("$in", 764)));
orList.add(new BasicDBObject("key2", new BasicDBObject("$in", list2)));
andList.add(new BasicDBObject("key2", 3));
andList.add(new BasicDBObject("key4", 67));
orList.add(new BasicDBObject("$and", andList));
BasicDBObject query = new BasicDBObject("$or", orList);