I'm using the Java driver with MongoDB. I have a List of document id's in a collection. I want to update a single field in every document that has an "_id" equal to one of the document id's in my List. In the below example, I tried something like this:
List<ObjectID> list = new ArrayList<ObjectID>();
list.append(new ObjectId("123"));
list.append(new ObjectId("456"));
list.append(new ObjectId("789"));
column.updateMulti(new BasicDBObject("_id", list),new BasicDBObject("$set",new BasicDBObject("field",59)));
My intentions are to update the documents with _id=123, _id=456 and _id=789, setting their "field" attribute to 59.
Am I going about this the right way?
I believe you need to make a couple changes:
BasicDBList list = new BasicDBList();
list.add( new ObjectId("123") );
// Add the rest...
DBObject inStatement = new BasicDBObject( "$in", list );
column.updateMulti( new BasicDBObject( "_id", inStatement ), new BasicDBObject( "$set", new BasicDBObject( "field", 59 ) );
Otherwise, with your current query, you're doing an equality comparison of the _id property against a list of _ids - not actually using the $in operator.
Related
I'm having a lot of trouble transforming my MongoDB Query into a Java one.
I've tried both QueryBuilder and DBObject and can't manage to make it work.
This is my MongoDB Query:
db.getCollection('myCollection_v2').find({
idCab:1,
cab: {
$elemMatch:{
idCat: ObjectId("14567823123688")
}
},
fMod: {
$gte: ISODate("2017-04-04T00:00:000Z"),
$lt: ISODate("2017-04-04T23:59:590Z")
}
})
My DBOBject approach has been this and the problem that I get is that I cannot append(object, object) but append(string, object) so I don't know how should I structure it:
BasicDBObject query = new BasicDBObject(
"idCab", "1")
.append( new BasicDBObject(
"cab", new BasicDBObject(
"$elemMatch", new BasicDBObject(
"idCat", categoria ))))
.append( new BasicDBObject(
"fMod", new BasicDBObject( "$gte", fechaInicio )
.append( "$lt", fechaFin )
)
);
For a QueryBuilder I have this and the problem is that I didn't manage to make the part about the $elemMatch...
QueryBuilder query = new QueryBuilder().start().and(
new QueryBuilder().start().put("idCab").is(String.valueOf(pIdPortal)).get(),
new QueryBuilder().start().put("fMod")
.greaterThan(fechaInicio).get(),
new QueryBuilder().start().put("fMod")
.lessThan(fechaFin).get();
Could you help me, please? I'm going from a 50-50 love/hate relationship with MongoDB to a 100 hate relationship...
your DBObject is not properly formed. Your trying to pass a BasicDBObject as key instead of passing a String .
Just remove the two extra BasicDBObject like this :
BasicDBObject query = new BasicDBObject(
"idCab", 1)
.append("cab", new BasicDBObject(
"$elemMatch", new BasicDBObject(
"idCat", categoria)))
.append("fMod", new BasicDBObject("$gte", fechaInicio)
.append("$lt", fechaFin)
);
I have a mongo document that I am trying to update before insert in mongodb.
I have to put theses 3 keys
document._parentId = ObjectId()
document.aDictionnary.actionId = Integer
document.aDictionnary.bDictionnary.id = Integer
I have tried a few combinaison, but can't make it work.
Here is my current code
myClass.getDocument().append( "$set", new BasicDBObject().append("_parentId", myClass.getDocument.getId() ) );
myClass.getDocument().append( "$set", new BasicDBObject().append("aDictionnary", new BasicDBObject().append("actionId", actionToAttachId ) ) );
if( null == myClass.getSiteId() )
{
myClass.getDocument().append( "$set", new BasicDBObject().append("aDictionnary", new BasicDBObject().append("bDictionnary", new BasicDBObject().append( "id", actionToAttach.getSiteId() ))));
}
I don't want to directly update my document in database, reason is I keep all the history so each entry is a new insert.
Application doesn't crash, but fail on insert because of a wrong "append" syntax
Also I think it's unpleasing to write that kind of code because of the nested basicdbobject.append syntax, is there another way to do so ?
Here is the stack trace
163530 [http-8080-8] ERROR com.myapp.persistance.mystuff.MyClassMongo - java.lang.IllegalArgumentException: fields stored in the db can't start with '$' (Bad Key: '$set')
Have you tried the $push operator?
Example:
db.students.update({ _id: 1 },{ $push: { scores: 89 }})
In your example:
document._parentId = ObjectId()
document.aDictionnary.actionId = Integer
document.aDictionnary.bDictionnary.id = Integer
Essentially that equates to:
{_parentId: ObjectId(), aDictionary: {actionId: actionId,
bDictionnary: {id: id}}
So there are 3 documents - the toplevel all the way down to the nested bDictionnary. Each one of these is a DBObject so you'd need to build up the DBObject and save it as appropriate - here is some untested pseudo code:
DBObject myDocument = new BasicDBObject();
myDocument.put("_parentId", ObjectId())
DBObject aDictionary = new BasicDBObject("actionId", actionId)
.append("bDictionary", new BasicDBObject("id", id))
myDocument.put("aDictionary", aDictionary)
db.save(myDocument)
I am new to MongoDB. By default, collections in mongodb have index on _id field.I need to create an index on 2 more fields using Java.
DBObject indexOptions = new BasicDBObject();
indexOptions.put(field_1, 1);
indexOptions.put(field_2, -1);
collection.createIndex(indexOptions )
When i query that in mongodb using db.collection_name.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "schema.collection_name"
},
{
"v" : 1,
"key" : {
"field_1" : 1,
"field_2" : -1
},
"name" : "field_1_1_field_2_-1",
"ns" : "schema.collection_name"
}
]
I am not sure if the above is correct.
Can someone please confirm? If not correct,how can i correct it ?
Adding to the above, for retrieval i am doing something like this:
DBObject subscriberIdObj = new BasicDBObject( field3, value3 );
DBObject subscriberIdIsNullObj = new BasicDBObject( field3, null );
BasicDBList firstOrValues = new BasicDBList();
firstOrValues.add( subscriberIdObj );
firstOrValues.add( subscriberIdIsNullObj );
DBObject firstOr = new BasicDBObject( "$or", firstOrValues );
DBObject batchIdObj = new BasicDBObject( field1, value1 );
DBObject fileNameObj = new BasicDBObject( field2, value2 );
BasicDBList secondOrValues = new BasicDBList();
secondOrValues.add( batchIdObj );
secondOrValues.add( fileNameObj );
DBObject secondOr = new BasicDBObject( "$or", secondOrValues );
BasicDBList andValues = new BasicDBList();
andValues.add( firstOr );
andValues.add( secondOr );
DBObject query = new BasicDBObject( "$and", andValues );
DBCursor cursor = mongoDatastore.getDB().getCollection(collection_name).find(query);
Now, for fast retrieval like above should i create index separately on field1,field2 and field3? or compound index on all the 3 fields?
This is correct and is called Compound Index. You have created an index on two fields: field_1 (ascending) and field_2 (descending). So for example if you will sort by field_1 ascending and field_2 descending or by field_1 descending and field_2 ascending, MongoDb will use this index field_1_1_field_2_-1 for it.
However, the above index cannot support sorting by ascending field_1 values and then by ascending field_2 values. Also if you search or sort only on field_2, it will not use this index. In this case you can create a separate indexes for field_1 and field_2.
To check if your query is using index, try to use explain() and see which cursor is used. For example, you can try such query:
db.your_collection.find({ "field_1" : "something" }).explain()
If you will see that the cursor which is used is BtreeCursor, then the query uses the index, in case of BasicCursor it does not.
For more information, just refer to this article.
using mongodb shell, I am able to perform an aggregation query that retrieves the whole document.
In order to do that I use the $$ROOT variable.
db.reservations.aggregate([
{ $match : { hotelCode : "0360" } },
{ $sort : { confirmationNumber : -1 , timestamp: -1 } },
{ $group : {
_id : "$confirmationNumber",
timestamp :{$first : "$timestamp"},
fullDocument :{$first : "$$ROOT"}
}}
])
It retrieves objects whose content is confirmationNumber, timestamp, fullDocument.
fullDocument is the whole document.
I am wondering if it is possible to do the same with Spring-Data and the aggregation framework.
My java code is:
TypedAggregation<ReservationImage> aggregation = newAggregation(
ReservationImage.class,
match(where("hotelCode").is(hotelCode)),
sort(Direction.DESC,"confirmationNumber","timestamp"),
group("confirmationNumber").
first("timestamp").as("timestamp").
first("$$ROOT").as("reservationImage"));
List<myClass> items = mongoTemplate.aggregate(
aggregation,
myClass.class).getMappedResults();
the error is :
org.springframework.data.mapping.PropertyReferenceException: No property $$ found for type myClass
Do you have any ideas?
Thanks.
We created https://jira.spring.io/browse/DATAMONGO-954 to track the support for accessing System Variables from MongoDB Pipeline expressions.
Once that is in place, you should be able to write:
Aggregation agg = newAggregation( //
match(where("hotelCode").is("0360")), //
sort(Direction.DESC, "confirmationNumber", "timestamp"), //
group("confirmationNumber") //
.first("timestamp").as("timestamp") //
.first(Aggregation.ROOT).as("reservationImage") //
);
I've seen this sort of thing before and it is not just limited to variable names such as $$ROOT. Spring data has it's own ideas about how to map "properties" of the document in the pipeline. Another common problem is simply projecting a new or calculated field that essentially has a new "property" name to it that does not get recognized.
Probably the best approach is to "step down" from using the helper classes and methods and construct the pipeline as BSON documents. You can even get the underlying collection object and the raw output as a BSON document, yet still cast to your typed List at the end.
Mileage may vary to your actual approach,but essentially:
DBObject match = new BasicDBObject(
"$match", new BasicDBObject(
"hotelCode", "0360"
)
);
DBObject sort = new BasicDBObject(
"$sort", new BasicDBObject(
"cofirmationNumber", -1
).append("timestamp", -1)
);
DBObject group = new BasicDBObject(
"$group", new BasicDBObject(
"_id", "confirmationNumber"
).append(
"timestamp", new BasicDBObject(
"$first", "$timestamp"
)
).append(
"reservationImage", new BasicDBObject(
"$first", "$$ROOT"
)
)
);
List<DBObject> pipeline = Arrays.asList(match,sort,group);
DBCollection collection = mongoOperation.getCollection("collection");
DBObject rawoutput = (DBObject)collection.aggregate(pipeline);
List<myClass> items = new AggregationResults(List<myClass>, rawoutput).getMappedResults();
The main thing is moving away from the helpers that are getting in the way and constructing the pipeline as it should be free of the imposed restrictions.
Im using java/mongodb. I would like to create a table (collection) with some users. Well, its working im just not sure about my coding style. Could be this good if i just want to add 3 new persons to the collection?
BasicDBObject doc = new BasicDBObject();
doc.put("name", "klaus");
doc.put("age", 30);
doc.put("city", "new york");
col.insert(doc);
BasicDBObject doc2 = new BasicDBObject();
doc2.put("name", "mirko");
doc2.put("age", 23);
doc2.put("city", "madrid");
col.insert(doc2);
BasicDBObject doc3 = new BasicDBObject();
doc3.put("name", "jon");
doc3.put("age", 34);
doc3.put("city", "unknown");
col.insert(doc3);
Its look so "long". To add only 3 Persons I have to create always a new BasicDBObject and insert it with the same line code (col.insert(bla))? It cant be ^^ And an other question too: At the first time(doc) im adding name, age and city as column. Why do I have to add "name", "age" and "city" again and again... I just want to add "mirko", 23 and "madrid" for doc2.
The last thing what bugs me is that I can add a new Dokument to the Collection with the same(!) values. I could add a new jon with 34 years and the same city. Is this ok? And if yes, I would like to change it. Howto?
Thank you!
Use json for it..
String json = "{'key' : 'value'}"; /* Create json formatted data here */
DBObject dbObject = (DBObject)JSON.parse(json);
collection.insert(dbObject);
No need to execute insert several times. You can make one insert call for collection of objects:
http://api.mongodb.org/java/2.0/com/mongodb/DBCollection.html#insert(java.util.List)
For example:
List<BasicDBObject> docs = new ArrayList<BasicDBObject>();
BasicDBObject doc = new BasicDBObject();
doc.put("name", "klaus");
doc.put("age", 30);
doc.put("city", "new york");
docs.add(doc);
BasicDBObject doc2 = new BasicDBObject();
doc2.put("name", "mirko");
doc2.put("age", 23);
doc2.put("city", "madrid");
docs.add(doc2);
BasicDBObject doc3 = new BasicDBObject();
doc3.put("name", "jon");
doc3.put("age", 34);
doc3.put("city", "unknown");
docs.add(doc3);
col.insert(docs);
You can always try Morphia,a java library, for MongoDB. It lets you save, retrieve and update POJO objects as documents.
For your second query related to collections with same values, in mongoDB you have the option to use unique indexes which makes sure no two records of same values are inserted in the collection