Check if Document in MongoDB exists, using reactive-streams - java

I'm trying to check if a document already exits, but I'm having some problems.
I tried different solutions:
Using findOne() and checking if output is null (doesn’t work)
Using countDocument() (doesn’t work)
The error that is saw the most is that I can’t cast for example: Publisher to long or Publisher to Document
Thanks.
Method 1:
Document d = collection.find(eq("UUID", id)).first();
if (d == null) {
System.out.println("document = null");
return;
}
System.out.println("document exists");
Method 2:
if (collection.countDocuments(query) < 1) {
System.out.println("Document exists");
}

To check if a document exists you can use the exists() method from the ReactiveMongoTemplate class. The method takes a Query object as its parameter, which is used to specify the conditions to match the document. You can read about the exists() method right here.
Here is an example of how you can use the exists() method to check if a document with a specific id field exists in a collection called docs:
Query query = new Query(Criteria.where("id").is("unique-id-123"));
Mono<Boolean> exists = reactiveMongoTemplate.exists(query, “docs”);
Where query is org.springframework.data.mongodb.core.query.Query and reactiveMongoTemplate is org.springframework.data.mongodb.core.ReactiveMongoTemplate
Another solutions that you mentioned actually have to work too, for example:
Using findOne() method:
Query query = new Query(Criteria.where("id").is("unique-id-123"));
Mono<Document> documentMono = reactiveMongoTemplate.findOne(query, Document.class, "docs");
documentMono.subscribe(doc -> {
if (doc != null) {
System.out.println("Document exists!");
} else {
System.out.println("Document does not exist!");
}
});
You can read about findOne() method here.
Update for [1]: findOne():
As kerbermeister mentioned, That approach will not work:
reactor does not allow null values, so if publisher completes with empty, there will be no null value
and
When Publisher completes with empty it instantly completes with onComplete signal, not onNext. Also, as documentation of subscribe(Consumer) suggests: consumer – the consumer to invoke on each value (onNext signal). So this callback will never be called if publisher completes with empty.
Using count() method:
Query query = new Query(Criteria.where("id").is("unique-id-123"));
Mono<Long> count = reactiveMongoTemplate.count(query, "docs");
count.subscribe(cnt -> {
if (cnt > 0) {
System.out.println("Document exists!");
} else {
System.out.println("Document does not exist!");
}
});
You can read about count() method here

Related

Trying to update a document using MongoDB Java Driver

Thank you
I just want to thank you for clicking on this question! I've tried my best to make this as thorough as possible.
but still, feel free to let me know if you need to clarify anything further!
if you think the question is too long. you can just read the third & fourth part and post your own solution down here!
Setup
Mongodb Java driver: org.mongodb:mongo-java-driver:3.11.0-rc0
What I want to do
find a specific document with a specific "name" field.
then update the other field or the whole document.
Example Document
// the document that I am trying to find in db
{
"_id":"5de6af7cfa42833bd9849477",
"name":"Richard Koba",
"skills":[]
}
// the document that I have
{
"name":"Richard Koba",
"skills":[jump, dance, sing]
}
// final result in db
{
"_id":"5de6af7cfa42833bd9849477",
"name":"Richard Koba",
"skills":[jump, dance, sing]
}
What I am doing now
// finding a document with same "name" field as input doc and update it with doc
public MongoCollection updateDocument(Document doc, String colName) {
MongoCollection collection;
// make sure collection exist
try {
collection = connectCollection(colName); // returns MongoCollection Obj
} catch (CollectionNotFoundException e) {
MessageHandler.errorMessage(e.getMessage());
return null;
}
// trying to find the document.
if (collection.find(eq("name", doc.get("name"))).first() == null) {
// if document not found, insert a new one
collection.insertOne(doc);
} else {
// if the document found, replace/update it with the one I have
collection.replaceOne(eq("name", doc.get("name")), doc);
}
return collection;
}
What I found about my false solution
collection.find(eq("name", doc.get("name"))).first() never returns null.
Java only tells me it returns an Object. MongoDB Documentation tells me it is a TResult, which point back to MongoIterable<TResult>. I am stuck here.
the code outcome is that none of the documents is inserted/updated in the end.
Reference
https://mongodb.github.io/mongo-java-driver/3.11/javadoc/com/mongodb/client/MongoIterable.html#first()
I tried some code and this works fine. This is not much different from your code.
Created a document from mongo shell:
MongoDB Enterprise > db.users.findOne()
{
"_id" : "5de6af7cfa42833bd9849477",
"name" : "Richard Koba",
"skills" : [ ]
}
My Java Code:
// Test input documents
private Document doc1 = new Document()
.append("name", "Richard Koba")
.append("skills", Arrays.asList("jump", "dance", "sing"));
private Document doc2 = new Document()
.append("name", "Richard K")
.append("skills", Arrays.asList("sings"));
When doc1 is passed to the following method the result is: "### Doc FOUND". And, with doc2 the result is "### Doc NOT found".
private void checkDocument(Document doc) {
MongoClient mongoClient = MongoClients.create("mongodb://localhost/");
MongoDatabase database = mongoClient.getDatabase("javadb");
MongoCollection<Document> collection = database.getCollection("users");
if (collection.find(eq("name", doc.get("name"))).first() == null) {
System.out.println("### Doc NOT found");
}
else {
System.out.println("### Doc FOUND");
}
}
I also tried this, with the same results.
Document d = collection.find(eq("name", doc.get("name"))).first();
if (d == null) { // ... }
I also tried this; works fine too.
if (collection.find(queryFilter).iterator().tryNext() == null) { // ... }
I think there might be some other issue with your code or the database / collection. Some debugging and testing with new data might reveal the real issue.
Did you check if the document already exists in the collection, from mongo shell or Compass tools?
Are you using the right database and collection names?
After each test run are you verifying the data in the database if it is updated / inserted?
collection.find(eq("name", doc.get("name"))).first() never returns
null.
With the code I posted above, the find query did return null when the users collection was empty.
collection.find() return an array of documents. What you actually want here is collection.findOneAndUpdate()
After you get a TDoucment object from findOneAndUpdate, you can use a ObjectMapper e.g.jackson to map it back to a java object

document locking returns not expected value

I have a function in which I would like to check if a user can set a lock on document. If so I know the user can edit the document.
public boolean canWriteDocument(String docId, String userName) {
boolean canWrite = false;
Session session = null;
session = getCurrentSession();
try {
Database db = session.getDatabase("", this.activeDb);
if (db.isDocumentLockingEnabled()) {
//Document locking is enabled
Document doc = db.getDocumentByUNID(docId);
if (doc.lock(userName)) {
canWrite = true;
System.out.println("document can be locked by user");
doc.unlock();
} else {
System.out.println("document can NOT be locked by user");
}
} else {
//Document locking is NOT enabled
}
} catch (NotesException e) {
// fail silently
System.out.println("failure docLock");
//e.printStackTrace();
}
return canWrite;
}
I call the function as followed:
canWriteDocument("99DE330A432849AFC125803400313C73", "CN=John Doe/O=quintessens")
However there must be something wrong because when the user (with ACL Author access level) is not listed in the field of type Authors it returns true.
When I lower the ACL access level to Reader the returned value is still true.
Anyone can explain why this is happening?
It may be that the database access level is cached within the server. Try rebooting the server (if it's a development environment) or testing with a brand new user that has never been in the ACL before.
If Database.queryAccess() is also not correct, that would confirm caching is the issue.
(It's possible that the two ways of checking access work differently under the hood, so if queryAccess() returns the correct value, it may not categorically mean the database locking option should.)

Java - LDAP: Attribute is Read-Only

I am using UnboundID-LDAPSDK (2.3.8) to change the user's photo in our Microsoft Active Directory.
LDAPConnection ldap = null;
try {
ldap = new LDAPConnection("domain-srv", 389, "CN=admin,OU=Users,OU=ADM,DC=domain,DC=local", "password");
SearchResult sr = ldap.search("DC=domain,DC=local", SearchScope.SUB, "(sAMAccountName=" + getUser().getUsername() + ")");
if (sr.getEntryCount() == 1) {
SearchResultEntry entry = sr.getSearchEntries().get(0);
entry.setAttribute("thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.close();
return true;
} else
return false;
} catch (LDAPException e) {
e.printStackTrace();
}
But I get a java.lang.UnsupportedOperationException.
The documentation for setAttribute states:
Throws an UnsupportedOperationException to indicate that this is a
read-only entry.
I also tried to change the postalCode but I get the same exception.
Changing those attributes should be possible, because I can change them with jXplorer.
Do I have to enable a write-mode somehow?
Thank you
The SearchResultEntry object extends ReadOnlyEntry and is therefore immutable. But even if it weren't, merely calling entry.setAttribute would have no effect on the data in the server. You have to use a modify operation for that.
To do that, you'd need something like:
ModifyRequest modifyRequest = new ModifyRequest(entry.getDN(),
new Modification(ModificationType.REPLACE,
"thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.modify(modifyRequest);
Also, you should put the call to ldap.close() in a finally block because as the code is written now, you're only closing the connection if the search is successful and returns exactly one entry, but not if the search fails, doesn't match any entries, or the attempt to perform the modify fails.

How to get if a code exist in parse.com?

I have a problem, I have this structure in parse.com in "VerificationCode" db:
When someone inserts a code in my app, it automatically adds in the "attachedUser" column the id of the user who is stored locally and I call it "ParseInstallObject.codigo2" and I get the id of the user for example to see it in a textview, etc.
The problem is that I want to check if the user id exists in parse or not; and if it exists do something or if not exist do another thing.
I used a code that I see in the documentation of parse.com but it always shows that the code exists. This is my code:
ParseQuery<ParseObject> query2 = ParseQuery.getQuery("VerificationCode");
query2.whereEqualTo("attachedUser", ParseInstallObject.codigo2);
query2.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> scoreList, ParseException e) {
if (e == null) {
comprobar.setText("exist");
comprobar2.setText("exist");
} else {
comprobar.setText("no exist");
comprobar2.setText("no exist");
}
}
});
How can I see if the user has a valid code or not?
e==null means that the call was successfully completed by the server. It does not imply that the user exists or not.
if(e==null){
if(scoreList == null || scoreList.isEmpty()){
// The user does not exist.
}else{
// the user exists.
}
}else {
// You have an exception (like HTTPTimeout, etc). Handle it as per requirement.
}

Java Neo4j Deletion and Internal 500 Errors

When I delete my neo4j database after my tests like this
public static final DatabaseOperation clearDatabaseOperation = new DatabaseOperation() {
#Override public void performOperation(GraphDatabaseService db) {
//This is deprecated on the GraphDatabaseService interface,
// but the alternative is not supported by implementation (RestGraphDatabase)
for (Node node : db.getAllNodes()) {
for (Relationship relationship : node.getRelationships()) {
relationship.delete();
}
boolean notTheRootNode = node.getId() != 0;
if (notTheRootNode) {
node.delete();
}
}
When querying the database through an ajax search (i.e searching on an empty database it returns an internal 500 error)
localhost:9000/search-results?keywords=t 500 Internal Server Error
197ms
However if I delete the database manually like this
start r=relationship(*) delete r;
start n=node(*) delete n;
No exception is thrown
Its most likely an issue with my code at a lower level in the call and return.
Just wandering why the error only works on one of the scenarios above and not both
Use cypher,
you should probably state more obviously that you use the rest-graph-database.
Are you querying after the deletion or during it?
Please check your logs in data/graph.db/messages.log and data/log/console.log to find the error cause.
Perhaps you can also look at the response body of the http-500 request
As per your error I guess your data is getting corrupted after deletion.
I have used same code like yours and deleted the nodes, except I put the Iterator in transaction and shut down the database after opetation.
e.g.
Transaction _tx = _db.beginTx();
try {
for ( your conditions){
Your code
}
_tx.success();
} catch (Exception e) {
_logger.error(e.getMessage());
}finally{
_tx.finish();
_db.shutdown();
graphDbFactory.cleanUp();
}
Hope it will work for you.

Categories