I've got a question about $currentDate
What is the best way to insert a document in mongo db so that it contains the "server time" (like ''now()'' in some RDBMSs) using the Java Driver?
For example, lest say I have a document like:
{
name : "John",
birthday : <$currentDate_goes_here>
}
What I want is to insert the document so that the evaluation of the date would be done by mongo server at the time of insertion on the server side.
This is critical because our servers might not be totally synchronized and there is a need to have the time we can rely on (for example the time on mongo server).
I'm using a standard java driver for mongo, so any code snippet in Java will be more than welcome.
This is what I've tried so far
MongoClient mongoClient = new MongoClient();
DB sampleDB = mongoClient.getDB("sampleDB");
BasicDBObject update =
new BasicDBObject("$set", new BasicDBObject("name","john")
.append("$currentDate", new BasicDBObject("birthday",true)));
sampleDB.getCollection("col1").insert(update);
This thing fails on the following exception:
java.lang.IllegalArgumentException: Document field names can't start with '$' (Bad Key: '$set')
at com.mongodb.DBCollection.validateKey(DBCollection.java:1845)
at com.mongodb.DBCollection._checkKeys(DBCollection.java:1803)
at com.mongodb.DBCollection._checkObject(DBCollection.java:1790)
at com.mongodb.DBCollectionImpl.applyRulesForInsert(DBCollectionImpl.java:392)
at com.mongodb.DBCollectionImpl.insertWithCommandProtocol(DBCollectionImpl.java:381)
at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:186)
at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:165)
at com.mongodb.DBCollection.insert(DBCollection.java:93)
at com.mongodb.DBCollection.insert(DBCollection.java:78)
at com.mongodb.DBCollection.insert(DBCollection.java:120)
In which case the answer is fairly simple. It is really about serializing from java BasicDBObject classes to the basic MongoDB interpretation. Without respect to your actual "query" document the "update" document part of your statement should be:
BasicDBObject update = new BasicDBObject("$set", new BasicDBObject("name","john")
.append("$currentDate", new BasicDBObject("birthrhday",true))
;
Which will indeed use the "server time" at the point of "update insertion" or "modification" with respect to the $currentDate modifier as used.
Just to be clear here, you don't use the .insert() method but an "upsert"operation with .insert(). The "query" and "update" syntax applies. Also see the $setOnInsert operator for specifically not modifying existing documents.
You can also use aggregation variable "$$NOW" if you are using an aggregation pipeline with update method.
MongoClient mongoClient = new MongoClient();
DB sampleDB = mongoClient.getDB("sampleDB");
BasicDBObject update =
new BasicDBObject("$set", new BasicDBObject("name","john")
.append("birthday", new BsonString("$$NOW")));
sampleDB.getCollection("col1").updateOne(query, List.of(update));
You can also use "$$NOW" with aggregation operators such as $add, $subtract, and many more, to compute more specific values (including dates) on the database side.
If you want to pass the Application Server's time instead of Database time, use the following code to send the current time. You should decide whether to use this in case if the Application Server time differs from Database Server time.
new BsonDateTime(Instant.now().toEpochMilli())
Sample Code:
MongoClient mongoClient = new MongoClient();
DB sampleDB = mongoClient.getDB("sampleDB");
BasicDBObject update =
new BasicDBObject("$set", new BasicDBObject("name","john")
.append("birthday", new BsonDateTime(Instant.now().toEpochMilli())));
sampleDB.getCollection("col1").updateOne(query, update);
Related
I have a local MongoDB instance running via shell on windows 10.
University provided a Java Project for us to learn about queries.
Now, I have a database ("imdb") and want to get two collections from it ("movies","tweets").
The problem is, one the one hand
List<String> test = mongo.getDatabaseNames();
System.out.println(test); //prints [admin,config,imdb,local]
...
db = mongo.getDB("imdb");
System.out.println(db.getCollectionNames()); //prints []
There seem to be no collections on imdb but
db.createCollection("movies", new BasicDBObject());
Returns a com.mongodb.CommandFailureException, stating that a collection 'imdb.movies' already exists.
So how do I ensure that Java actually "loads" the Collections?
For Clarification: My goal is to have
System.out.println(db.getCollectionNames());
to print [movies,tweets] instead of []
You could try
Set<String> colls = db.getCollectionNames();
for (String s : colls) {
System.out.println(s);
}
ref: code examples
Which version of mongodb shell you're using
If it's before 3.0, it will return no data for db.getCollectionNames() command
ref: mongodb docs
Since version 3.0 you should use MongoDatabase.listCollectionNames() method.
http://mongodb.github.io/mongo-java-driver/3.8/driver/tutorials/databases-collections/#get-a-list-of-collections
MongoDatabase db = client.getDatabase(dbName);
MongoIterable<String> names = db.listCollectionNames();
You can do like this:
//If you don't need connection's configures. i.e. your mongo is in you localhost at 127.0.0.1:27017
MongoClient cliente = new MongoClient(); //to connect into a mongo DB
MongoDatabase mongoDb = client.getDatabase("imdb"); //get database
MongoCollection<Document> robosCollection = mongoDb.getCollection("movies"); //get the name of the collection that you want
MongoCursor<Document> cursor = robosCollection.find().cursor();//Mongo Cursor interface implementing the iterator protocol
cursor.forEachRemaining(System.out::println); //print all documents in Collection using method reference
I can drop a database with the following statement:
MongoClient mongo = new MongoClient("localhost", 27017);
mongo.dropDatabase("d");
How can I create a database?
If you are using driver 3.1.1 or later:
Refer to this answer:
Calling getDatabase doesn't in fact create new database because
operation is lazy - it returns database representation. Calling any
modifiable operation (e.g. createCollection):
will create new database for you if it is not present if present it
will get database for you But remember that you have to call any
operation which actually performs something - like create. If you just
call getDatabase it won't create it.
NOTE
The documentation does not provide this information, hopefully, they update it. But long answer short, it only creates it after you call an operation on it.
MongoClient mongoClient = new MongoClient();
DB db = mongoClient.getDB("database name");
If database is not present, MongoDB will create it for you.
the mongo java driver has an old (and through deprecation of MongoClient.getDB essentially deprecated) method to explicitly perform a parallel scan on a collection.
As far as I can see, this is something along the lines of:
DB db = mongoClient.getDB("mydb");
DBCollection coll = db.getCollection("testCollection");
ParallelScanOptions parallelScanOptions = ParallelScanOptions
.builder()
.numCursors(4)
.batchSize(1000)
.build();
List<Cursor> cursors = coll.parallelScan(parallelScanOptions);
...
The question is: is there a new alternative in driver 3.2 (without using the deprecated DB API)?
You can utilise runCommand() to execute parallelCollectionScan command directly.
For example:
MongoClient client = new MongoClient(new ServerAddress());
MongoDatabase database = client.getDatabase("databaseName");
Document commandResult = database.runCommand(new Document("parallelCollectionScan", "collectionName").append("numCursors", 3));
See also cursor batches
What I am trying to accomplish here is pretty simple. I am trying to update a single document in MongoDB collection. When I look up the document using any field, such as "name", the update query succeeds. Here is the query:
mongoDB.getCollection("restaurants").updateOne(
new BasicDBObject("name", "Morris Park Bake Shop"),
new BasicDBObject("$set", new BasicDBObject("zipcode", "10462"))
);
If I try to lookup the document with the ObjectId, it never works as it doesn't match any document.
mongoDB.getCollection("restaurants").updateOne(
new BasicDBObject("_id", "56110fe1f882142d842b2a63"),
new BasicDBObject("$set", new BasicDBObject("zipcode", "10462"))
);
Is it possible to make this query work with Object IDs?
I agree that my question is a bit similar to How to query documents using "_id" field in Java mongodb driver? however I am not getting any errors while trying to update a document. It just doesn't match anything.
You're currently trying to update based on a string, not an ObjectId.
Make sure to initialise a new ObjectId from the string when building your query:
mongoDB.getCollection("restaurants").updateOne(
new BasicDBObject("_id", new ObjectId("56110fe1f882142d842b2a63")),
new BasicDBObject("$set", new BasicDBObject("zipcode", "10462"))
);
#sheilak's answer is the best one but,
You could use {"_id", {"$oid","56110fe1f882142d842b2a63"}} as the filter for the update query if you want it to be in the string format
Convert the string to objectid:
from bson.objectid import ObjectId
db.collection.find_one({"_id":ObjectId('5a61bfadef860e4bf266edb2')})
{u'_id': ObjectId('5a61bfadef860e4bf266edb2'), ...
what is the idiomatic way to upsert a document using version 3 of the mongodb java driver (specifically v3.0.1)?
We have a collection for sessions and when a new session gets created or modified, we want to upsert it in one operation - rather than having to query if a document exists yet and then either inserting or replacing.
Our old upsertion code used the scala driver casbah 2.7.3. It looked like:
import com.mongodb.casbah.MongoCollection
import com.mongdb.DBObject
val sessionCollection: MongoCollection = ...
val sessionKey: String = ...
val sessionDocument: DBObject = ... // Either create a new one, or find and modify an existing one
sessionCollection.update(
"_id" -> sessionKey,
sessionDocument
upsert = true
)
In our current project we're just using the plain java 3.0.1 driver and we're using BsonDocument instead of DBObject to make it more typsafe. I tried to replace the above with something like:
import com.mongodb.client.MongoCollection
val sessionCollection: MongoCollection = ...
val sessionKey: String = ...
val sessionDocument: BsonDocument = // Either create a new one, or find and modify an existing one
val updateOptions = new UpdateOptions
updateOptions.upsert(true)
sessionCollection.updateOne(
"_id" -> new BsonString(sessionKey),
sessionDocument,
updateOptions
)
This throws the error "java.lang.IllegalArgumentException: Invalid BSON field name ...". The error is covered in this question but the op in that question wasn't trying to upsert in one operation - they were using context to decide whether to replace/update/insert etc...
I'm happy with code samples in scala or java.
Thanks!
In the Mongo Java Driver 3.0 series we added a new Crud API which is more explicit and therefore beginner friendly. This initiative has been rolled out over a number of MongoDB Drivers but it does contain some changes compared to the older API.
As you are not updating an existing document using an update operator, the updateOne method is not appropriate.
The operation you describe is a replaceOne operation and can be run like so:
sessionCollection.replaceOne(
"_id" -> new BsonString(sessionKey),
sessionDocument,
(new UpdateOptions()).upsert(true)
)