mongodb - Sub document id value - mongodb

I have a collection.
look
{ "_id" : 13.0 , "tenantref" : { "$id" : 3.0}}
I need to retrieve the value of id 3.0 using java.
I am getting null pointer exception.
BasicDBObject field = new BasicDBObject();
BasicDBObject field = new BasicDBObject();
field.put("tenantref.$id", 1);
DBCursor cursor = mongo.getDB("number").getCollection("testthree").find(query,field);
while (cursor.hasNext())
{
System.out.println(cursor.next().get("tenantref.$id"));
}
I am getting null pointer exception. How do I need to get the value?

cursor.next().get("tenantref.$id"));
The get() function of BasicDBObject does not support the dot syntax. You have to traverse the object hierarchy by hand. Try
((DBObject)cursor.next().get("tenantref")).get("$id");

Related

MongoDB project nested element in _id field

I'm stuck in something very stupid but I can't get out from my own.
MongoDB v4.2 and I have a collection with documents like this:
{"_id":{"A":"***","B":0}}, "some other fields"...
I'm working on top of mongo-c driver and I want to query only the "_id.B" field but I don't know how I can do it. I have tried:
"projection":{"_id.B":1}: It returns me the whole _id object. _id.A & _id.B.
"projection":{"_id.A":0,"All other fields except _id.B":0}: Returns same as above.
"projection":{"_id.A":0,"_id.B":1}: Returns nothing.
How I can do it to get only some object elements when this object is inside the _id field? The first option works for me with objects that aren't inside the _id field but not here.
Best regards, thanks for your time.
Héctor
You can use MongoDB's $project in aggregation to do this. You can also use $addFields to get _id.B into new field + all other fields in document & finally project _id :0.
Code:
var coll = localDb.GetCollection("yourCollectionName");
var project = new BsonDocument
{
{
"$project",
new BsonDocument
{
{ "_id.B": 1 }
}
}
}
var pipeline = new[] { project };
var result = coll.Aggregate(pipeline);
Test : MongoDB-Playground

Grails Mongo Low Level API

What would be the equivalent of this line in groovy code when using the Mongo low level API?
db.countrycodes.findOne({"Country":"Antarctica"})
This line successfully finds the appropriate record for me in the Mongo shell but I tried many variations of it in my controller method and I keep getting NULL. Heres is my current attempt which is failing:
MongoClient mongoClient = new MongoClient("localhost", 27017)
DB db = mongoClient.getDB("twcdb");
DBCollection coll = db.getCollection('countrycodes')
println coll.find("Country":"Antarctica")
I know my collection and db is non NULL because when I do find() I do get a valid cursor back through which I can print the first record in collection. Here is the record I am trying to find:
{
"_id" : ObjectId("539848b2119918654e7e90b1"),
"Country" : "Antarctica",
"Alpha2" : "AQ",
"Aplha3" : "ATA",
"Numeric" : "10",
"FIPS" : "AY",
"IGA" : ""
}
Try this:
def cursor = coll.find()
def obj = cursor.next()
while (obj.Country != 'Antarctica') {
obj = cursor.next()
}
It is inefficient, you will have to traverse the whole collection everytime to find a record, but it will end up with 'obj' being the record you need.
Try below code and see if it works.
BasicDBObject query = new BasicDBObject("Country", "Antartica");
def cursor = coll.find(query)
try {
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
} finally {
cursor.close();
}
For more info look here: http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-java-driver/

How to pass BasicDBList of $OR criteria to QueryBuilder?

My app is dynamically generating a mongo query via a QueryBuilder. I'm trying to make it so that the passed text can be compared against several fields in my collection. I need to iterate through data in order to know what to add to the $OR ( 'text_to_compare' vs title field, 'text_to_compare vs body field), so I've been trying to store each section of the $OR clause in a BasicDBList as follows:
BasicDBObject orsDBObject = new BasicDBObject();
BasicDBList orsList = new BasicDBList();
for( String dbFieldNameInstance: listDBFieldName ){
QueryBuilder innerQB = new QueryBuilder();
innerQB.put(dbFieldNameInstance).is(obj.getValue()); //using this inner QueryBuilder to assist in creating the document
orsList.add(innerQB.get());
}
orsDBObject.putAll(orsList); //put each of the BasicDBList items into a BasicDBObject
qb.or(orsDBObject); //finally, add the entire $OR clause to my bigger querybuilder
System.out.println("qb: " + qb.get());
It seems like I might be jumping through more conversions than are necessary. It isn't working either. The output from the above ends up looking like this:
qb: { "$or" : [ { "0" : { "primary_industries_names" : "electrical"} , "1" : { "primary_industries_aliases" : "electrical"} , "2" : { "secondary_industries_names" : "electrical"} , "3" : { "secondary_industries_aliases" : "electrical"} , "4" : { "product_experience_names" : "electrical"} , "5" : { "product_experience_aliases" : "electrical"}}]}
For the most part it looks right to me, however I don't think the "0": should be appearing in there. Any advice would be greatly appreciated.
You kind of have that the wrong way around. Not re-writing your code, but you should get the idea:
// Before the loop
QueryBuilder qb = new QueryBuilder();
// And loop things like this
for ( ) {
qb.or(new BasicDBObject("this","that"));
}
// After loop
System.out.println(qb.get());
If you are trying to nest several conditions then you seem to be missing the $and operator. Consider the following:
QueryBuilder qb = new QueryBuilder();
for (int x=0; x<2;x++) {
qb.or(new BasicDBObject("this","that"));
}
QueryBuilder qb2 = new QueryBuilder();
qb2.and(qb.get());
QueryBuilder qb3 = new QueryBuilder();
for (int x=0; x<2;x++) {
qb3.or(new BasicDBObject("something", "else"));
}
qb2.and(qb3.get());
System.out.println(qb2.get());

mongodb java to insert embedded document

I have a collection with embedded documents in it.
System
{
System_Info: ...,
Tenant: [
{
Tenant_Id: ...,
Tenant_Info: ...,
Prop_Info: ...
},
{
Tenant_Id: ...,
Tenant_Info: ...,
Prop_Info: ...
} ]
}
If I need to insert another tenant information like this
Tenant { Tenant_Id:2,Tenant_Info:"check",prop_info:"client"}.
whats the mongodb query to insert embedded documents? and how to do it using java?
Use the following code to insert into array :
BasicDBObject query = new BasicDBObject();
query.put( "System_Info", "...." );
BasicDBObject tenant = new BasicDBObject();
tenant.put("Tenant_Id", 2);
tenant.put("Tenant_Info", "check");
tenant.put("Prop_Info", "client");
BasicDBObject update = new BasicDBObject();
update.put("$push", new BasicDBObject("Tenant",tenant));
coll.update(query, update,true,true);
Are you trying to add another Tenant into the array? If so, you would want to create a DBObject representing the Tenant, and then $push it onto the array.
In Java, embedded documents are represented by DBObjects (of which BasicDBObject is a subclass). Here is an example of inserting an embedded document, from the docs:
http://www.mongodb.org/display/DOCS/Java+Tutorial#JavaTutorial-InsertingaDocument
Additionally, here is an example of using $push in Java:
Updating an array in MongoDB using Java driver
...and this is how to do it with mongo-driver version >= 3.1 (mine is 3.2.2):
Document tenant = new Document("Tenant_Id", 2)
.append("Tenant_Info", "check")
.append("Prop_Info", "client");
Bson filter = Filters.eq( "System_Info", "...." ); //get the parent-document
Bson setUpdate = Updates.push("Tenant", tenant);
coll.updateOne(filter, setUpdate);
Hope that helps someone.

Remove an array entry in an object using spring data mongodb

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