full text search with and condition - mongodb

Is it possible to include AND, OR, NOTIN conditions with text search in MongoDB?
e.g.
final DBObject textSearchCommand = new BasicDBObject();
textSearchCommand.put("text", "user");
textSearchCommand.put("search", fullTextSearch.text)
textSearchCommand.put("isDeleted", false)\\ this is AND condition here, but this does not work
final CommandResult commandResult = db.command(textSearchCommand);
Is there any work around for this ?

You have not maintained it clearly that do you want AND operation for all fields or you want first two fields in OR Operation and last fields i.e isDeleted is in AND operation with first two.
I'm considering you want All Three Fields in AND Operation
You case use AND , OR operator in mongodb to query on full text.
NOTIN i.e. $nin operator you have to use with particular field.
Below is code with $and operator in mongodb
final BasicDBList textSearchCommand = new BasicDBList();
/* List is used to add element */
textSearchCommand.add( new BasicDBObject("text", "user"));
textSearchCommand.add( new BasicDBObject("search", fullTextSearch.text));
textSearchCommand.add( new BasicDBObject("isDeleted", false));
BasicDBObject queryDoc = new BasicDBObject("$and", textSearchCommand);
/* Above Statement Adds and operator to query */
final CommandResult commandResult = db.command(queryDoc);
You can use $or same as like $and.
NotIn operator i.e. $nin used with particular field.
Following Are the links you can use reference.
And Operator : $and
OR Operator : $or
NOTIN Operator : $nin

Related

DataStax Stargate Document API

What does the a JSON blob with search filters, allowed operators: $eq, $ne, $in, $nin, $gt, $lt, $gte, $lte, $exists in the Swagger documentation that is shown in the DataStax Document API Swagger UI, it's not that documented so I want to ask if the query string is based on MongoDB?
The Document API exposed on top of Cassandra is provided by the open source project Stargate, indeed developed by Datastax and embedded in their Saas solution Astra.
The JSON query String than you created is parsed and converted in a proper CQL query under the hood.
Source code doesn't lie you can find the full code here and specially parsing of the where clause here
public List<FilterCondition> convertToFilterOps(
List<PathSegment> prependedPath,
JsonNode filterJson) {
List<FilterCondition> conditions = new ArrayList<>();
if (!filterJson.isObject()) {
throw new DocumentAPIRequestException("Search was expecting a JSON object as input.");
}
ObjectNode input = (ObjectNode) filterJson;
Iterator<String> fields = input.fieldNames();
while (fields.hasNext()) {
String fieldName = fields.next();
if (fieldName.isEmpty()) {
throw new DocumentAPIRequestException(
"The field(s) you are searching for can't be the empty string!");
}
...
The query string is pretty similar in spirit to what you'd find with Mongo.
Here are some sample where clauses to give an idea:
{"name": {"$eq": "Eric"}} - simple enough, matches documents that have a field name with value Eric
{"a.age": {"$gt": 0}} - You can also reference nested fields in a document
{"friends.[0].name": {"$in": ["Cassandra"]}} - Array elements are referenced using [], this would match if the document's first friend is named Cassandra.
{"friends.*.age": {"$gte": 24}} - Wildcard * can be used to match any element in an array, or any field at a particular level of nesting. This matches any friend whose age is >= 24.

Comparing field values in MongoDB

I wanted to run a query that finds the following document from MongoDB database
{field1:"foo",field2:"barfoobar"}
I know for equality I can use the following query:
.find({ $where : "this.field1 == this.field2" })
In C#
new BsonDocument("$where", new BsonJavaScript("this.field1 == this.field2"));
But how I can use regex in above query?
Somthing like:
.find({ $where : "this.field1 like this.field2" })
And in C# ?
Use the following query and check if it works for you. Let me know if it helped:
db.col.find( { $where: function() {
var regex = new RegExp(this.field1);
return (regex.test(this.field2))
} }).pretty();
The query above turns foo into a regex (something like /foo/) and checks if field2 matches the regex you passed.
FYI: The following statement was taken from mongodb website. Take it into consideration:
Changed in version 3.6: The $expr operator allows the use of aggregation expressions within the query language. $expr is faster than $where because it does not execute JavaScript and should be preferred where possible.

how to call count operation after find with mongodb java driver

I am using MongoDB 3.0. suppose there is a set of documents named photos, its structure is
{"_id" : 1, photographer: "jack"}
with database.getCollection("photos"), Mongodb will return a MongoCollection object, on which I have the method count() to get the number documents returned.
However, when I make queries with specific conditions. For example find documents with id smaller than 100 :
photosCollections.find(Document.parse("{_id : {$lt : 100}}"))
Above find method will always return a cursor which doesn't provide a count() function. So how can I know how many documents returned ? I know on command line, I can use
db.photos.find({_id : {$lt : 100}}).count()
Of course, I can go through the iterator and count the number of documents myself. However I find it really clumsy. I am wondering does MongoDB java driver provides such functionality to count the number of documents returned by the find() method ? If not, what is the reason behind the decision ?
As you said the MongoCollection has the count() method that will return the number of documents in the collection, but it has also a count(Bson filter) that will return the number of documents in the collection according to the given options.
So you can just use:
long count = photosCollections.count(Document.parse("{_id : {$lt : 100}}"))
or maybe clearer:
Document query = new Document("_id", new Document("$lt", 100));
long count = photosCollections.count(query);
ref: http://api.mongodb.com/java/3.3/com/mongodb/client/MongoCollection.html#count-org.bson.conversions.Bson-
In MongoDB 3.4 you can only use the Iterator of FindIterable to get the count of the documents returned by a filter. e.g.
FindIterable findIterable =
mongoCollection.find(Filters.eq("EVENT_TYPE", "Sport"));
Iterator iterator = findIterable.iterator();
int count = 0;
while (iterator.hasNext()) {
iterator.next();
count++;
}
System.out.println(">>>>> count = " + count);
I had a similar problem. I am using MongoCollection instead of DBCollection, as it is what it is used in MongoDG 3.2 guide. MongoCollection hasn't got count() method, so I think the only option is to use the iterator to count them.
In my case I only needed to know if any document has been returned, I am using this:
if(result.first() != null)
Bson bson = Filters.eq("type", "work");
List<Document> list = collection.find(bson).into(new ArrayList<>());
System.out.println(list.size());
into(A) (A is collection type) method iterates over all the documents and adds each to the given target. Then we can get the count of the returned documents.
The API docs clearly state that DBCursor Object provides a count method:
MongoClient client = new MongoClient(MONGOHOST,MONGOPORT);
DBCollection coll = client.getDB(DBNAME).getCollection(COLLECTION);
DBObject query = new Querybuilder().start()
.put("_id").lessThan(100).get();
DBCursor result = coll.find(query);
System.out.println("Number of pictures found: " + result.count() );

Comparison operator for the computed count value in MongoDB Aggregation Pipeline

I am using Aggregation Pipeline concept and below is the Java code which I used.
DBObject match = new BasicDBObject("$match",
new BasicDBObject("field_name", "value"));
DBObject group = new BasicDBObject("$group",
new BasicDBObject("_id" , "")
.append("count", new BasicDBObject("$sum", 1)));
The first pipeline operator "$match" will filter out documents. The second pipeline operator "$group" will give out the number of documents in the collection (In the above example). Let us say, the third pipeline operator is $project.
List<DBObject> pipeline = Arrays.asList(match, group, project);
AggregationOutput output = users.aggregate(pipeline);
The operation which I want to perform goes like this - I want to use $gte operator for the computed count value ( E.g., if { count : { $gte : 5 } } then continue to $project else exit).
Could anyone please help me out in solving this problem.
Use two queries: a count(), a check for the threshold, then a find() with a projection if necessary. You can't terminate the aggregation early based on some condition, as far as I know, so while I think you could construct a pipeline to quasi-fit your demands, really you should do the most natural thing. In the mongo shell since I don't have the Java driver handy to test with:
> var t = db.test.count({ "field" : "value" })
> if (t > 5) {
results = db.test.find({ "field" : "value"}, projection)
}
It's hard to give good code for this without knowing more about what your greater objective is.
I think you can use $match again as the third pipeline operator instead, link this: DBObject match2 = BasicDBObjectBuilder.start().push("$match").push("count").append("$gte", 5).get();

Document field names can't start with '$' (Bad Key: '$set')

BasicDBObject u = new BasicDBObject();
DBObject q = new BasicDBObject();
q.put("orgId", orgId);
u.append("orgId", orgId);
if(accounts.keySet().size() > 0) {
BasicDBObject setObj = new BasicDBObject();
for (String key : accounts.keySet()) {
String fieldToUpdate = "accounts." + key;
setObj.append(fieldToUpdate, accounts.get(key));
}
u.append("$set", setObj);
}
DBCollection collection = db.getCollection(collectionName);
WriteResult result = collection.update(q, u, true, false);
I get following error, what is wrong:
java.lang.RuntimeException: java.lang.IllegalArgumentException: Document field names can't start with '$' (Bad Key: '$set')
u.toString output is :
{ "orgId" : 2 , "$set" : { "accounts.001" : "EXAMPLE"}}
You should not have the { "orgId" : 2 } in the update document.
Remove this line from the code and it should work fine.
u.append("orgId", orgId);
The reason you triggered the error was that there are two ways to specify the update for a document and you created a cross bread of both. The options are:
Provide the complete document for the update. For this model the existing document is overwritten by the provided document.
Uses update operators to modify the existing document in the collection.
If you use the second version then all of the "top level keys" in the update document will start with a $. If you use the first option then none of the top level keys will start with a $. The code looked at the first field, thought it was a replacement document and then failed when it tried to validate the rest of the document was valid since keys in documents cannot start with a $ (lest the be confused with update or query documents).
Edit:
In the case of an upsert (e.g., the document does not already exist and you flag the update to allow the upsert) query's exact match operators are used to seed the document. For the above example we get a seed document of { "orgId" : 2 }. The server will then apply the update operators and save the result.