between (range) in mongodb query does not work - mongodb-query

I have a db doc as follow:
Now I am trying to group by all info by time between for 2 specific time and return the sum of count
for that I wrote my code as follow:
DBCollection coll = db.getCollection("test");
DBObject groupFields = new BasicDBObject("_id", "$time");
groupFields.put("sum", new BasicDBObject("$sum", "$count"));
DBObject group = new BasicDBObject("$group", groupFields);
// filter where clause
BasicDBObject simpleQuery = new BasicDBObject();
simpleQuery.put("time", new BasicDBObject("$gt", "20140005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
DBObject match = new BasicDBObject("$match", simpleQuery);
List<DBObject> pipeline = Arrays.asList(match, group);
AggregationOutput output = coll.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
when I run this code it group by all elements even those time that starts with 2013...but in simpleQuery I defined a range which apparently does not work . However as soon as I remove
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011")); the code starts working. Why does it happen ? Can anyone help?
Update1 :
it seems that in the following query the second one overwrite the first one:
simpleQuery.put("time", new BasicDBObject("$gt", "20140005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
because when I change the query it starts working
Update 2 :
when I change the code to the following it completely work:
BasicDBObject andQuery = new BasicDBObject();
simpleQuerytest.put("time", new BasicDBObject("$gt", "20130005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
obj.add(simpleQuerytest);
obj.add(simpleQuery);
andQuery.put("$and", obj);
Now my question is what is the difference between and query and just using put ? I always thought that they are the same !!! can anyone explain?

The reference variable simpleQuery points to an instance of BasicDBObject, which is an implementation of a Map. From the java docs, when you put a key value pair into the map, it,
Associates the specified value with the specified key in this map
(optional operation). If the map previously contained a mapping for
the key, the old value is replaced by the specified value. (A map m is
said to contain a mapping for a key k if and only if m.containsKey(k)
would return true.)
The first operation:
simpleQuery.put("time", new BasicDBObject("$gt", "20140005150011"));
associates the key time to a value.
The second operation,
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
replaces the previous value of the key time. Hence only the last inserted value of time gets associated to it.
The below operation works as intended because, simpleQuerytest and simpleQuery are two different Maps, which form the input to the map containing the and operation.
BasicDBObject andQuery = new BasicDBObject();
simpleQuerytest.put("time", new BasicDBObject("$gt", "20130005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
...
andQuery.put("$and", obj);

Related

Difference between two flux

I have two fluxes where order is not important and I want to get one resultant flux with the difference. How can I do this?
Example:
Flux<Tweet> remoteTweets = Flux.just(
new Tweet("tag1",new TweetID("text","name"),"userimage","country","place"),
new Tweet("tag2",new TweetID("text","name"),"userimage","country","place")
);
Flux<Tweet> localTweets = Flux.just(
new Tweet("tag1",new TweetID("text","name"),"userimage","country","place")
);
Result expected: tag2.
If localTweets is a finite stream and fits into memory, then the following works:
Flux<Tweet> remoteTweets = Flux.just(
new Tweet("tag1", new TweetID("text", "name"), "userimage", "country", "place"),
new Tweet("tag2", new TweetID("text", "name"), "userimage", "country", "place")
);
Flux<Tweet> localTweets = Flux.just(
new Tweet("tag1", new TweetID("text", "name"), "userimage", "country", "place")
).cache(); // note cache operator here, to avoid mutiple subscription
remoteTweets
.filterWhen(remoteTweet -> localTweets.hasElement(remoteTweet).map(hasElement -> !hasElement))
.subscribe(System.out::println);
If the stream is finite, but not fits into memory, then you should leave the cache operator out. That will mean localTweets Flux will be subscribed to multiple times.
If the stream is infinite, you should apply some windowing strategy (e.g. check tweets only from last 10 minutes).

how to update just one element of array when updating

I have a doc like the following:
as you can see I have an array entity: {1,3,4}
Now I want to just change 4 to 10 in that array and update it for that I have the following code:
DBCollection coll = db.getCollection("test");
BasicDBObject newDocument = new BasicDBObject();
BasicDBObject searchQuery = new BasicDBObject().append("time", "20141105230000");
coll.update(searchQuery, newDocument);
String[] str = { "1", "3", "10" };
DBObject updateMatchingElem = new BasicDBObject("$set",
new BasicDBObject().append("entity", str));
coll.update(searchQuery, updateMatchingElem);
But this way is not a good way because I kind of remove entity and then insert the whole array again. Is there anyway that I can just change the one element like 4 to 10?
Now I want to just change 4 to 10 in that array and update it
You can do it in the following way, using the $ positional operator.
//db.collection.update({"entity":4},{$set:{"entity.$":10}})
DBObject find = new BasicDBObject( "entity", 4);
DBObject set = new BasicDBObject( "entity.$", 10);
DBObject update = new BasicDBObject().append("$set", set);
coll.update(find, update);
Note that you can at most update only one single matching array element, even if there are other matching elements in the array. For instance, if there are two 4s in the array, only the first occurrence of 4 will get updated. This is how the positional operator works.
Whenever you use the positional operator in the update query, the find query must contain the field in the find part of the query.

Lucene DrillSideways with custom sort field or with TopScoreDocCollector

I am trying to implement drillsideways search with Lucene 4.6.1.
Following code works fine:
DrillSideways ds = new DrillSideways(searcher, taxoReader);
FacetSearchParams fsp = new FacetSearchParams(getAllFacetCounts());
DrillDownQuery ddq = new DrillDownQuery(fsp.indexingParams, mainQuery);
List<CategoryPath> paths = new ArrayList<CategoryPath>();
...
add category path
...
if (paths.size() >0)
ddq.add(paths.toArray(new CategoryPath[paths.size()]));
DrillSidewaysResult dsr = ds.search(null, ddq, 500, fsp); // <-- here
TopDocs topDocs = dsr.hits;
ScoreDoc[] hits = topDocs.scoreDocs;
// list search results
listSearchResults(searcher, hits, Math.min(500, topDocs.totalHits));
But what if I want to pass TopScoreDocCollector, like
// for now it is top score collector,
// but I may want to implement custom sort
TopScoreDocCollector topDocsCollector = TopScoreDocCollector.create(500, true);
DrillSidewaysResult dsr = ds.search(ddq, topDocsCollector, fsp);
the result is empty set and no errors. What is wrong?
I'm guessing you are referring to the value of DrillSidewaysResult.hits, and it is intended behavior, as noted in the documentation of DrillSidewaysResult:
Note that if you called DrillSideways.search(DrillDownQuery, Collector, FacetSearchParams), then hits will be null.
You should get your hits from the Collector instead.

Integer index behavior in neo4j + lucene

I want to index an integer field on nodes in a large database (~20 million nodes). The behavior I would expect to work is as follows:
HashMap<String, Object> properties = new HashMap<String, Object>();
// Add node to graph (inserter is an instance of BatchInserter)
properties.put("id", 1000);
long node = inserter.createNode(properties);
// Add index
index.add(node, properties);
// Retrieve node by index. RETURNS NULL!
IndexHits<Node> hits = index.query("id", 1000);
I add the key-value pair to the index and then query by it. Sadly, this doesn't work.
My current hackish workaround is to use a Lucene object and query by range:
// Add index
properties.put("id", ValueContext.numeric(1000).indexNumeric());
index.add(node, properties);
// Retrieve node by index. This still returns null
IndexHits<Node> hits = index.query("id", 1000);
// However, this version works
hits = index.query(QueryContext.numericRange("id", 1000, 1000, true, true));
This is perfectly functional, but the range query is really dumb. Is there a way to run exact integer queries without this QueryContext.numericRange mess?
The index lookup you require is an exact match, not a query.
Try replacing
index.query("id", 1000)
with
index.get("id", 1000)

How can I update document without losing fields?

CommonsHttpSolrServer server = new CommonsHttpSolrServer("http://localhost:8983/solr/");
SolrInputDocument doc1 = new SolrInputDocument();
doc1.addField("id", "id1");
doc1.addField("name", "doc1");
doc1.addField("price", new Float(10));
SolrInputDocument doc2 = new SolrInputDocument();
doc2.addField("id", "id1");
doc2.addField("name", "doc2");
server.add(doc1);
server.add(doc2);
server.commit();
SolrQuery query = new SolrQuery();
query.setQuery("id:id1");
query.addSortField("price", SolrQuery.ORDER.desc);
QueryResponse rsp = server.query(query);
Iterator<SolrDocument> iter = rsp.getResults().iterator();
while(iter.hasNext()){
SolrDocument doc = iter.next();
Collection fieldNames = doc.getFieldNames();
Iterator<String> fieldIter = fieldNames.iterator();
StringBuffer content = new StringBuffer("");
while(fieldIter.hasNext()){
String field = fieldIter.next();
content.append(field+":"+doc.get(field)).append(" ");
//System.out.println(field);
}
System.out.println(content);
}
The question is that I want to get the result "id:id1 name:doc2 price:10.0", but the output is "id:id1 name:doc2"...
So I want to know if I want to get the result as "id:id1 name:doc2 price:10.0", how can I modify my programming?
As you are adding the documents with same id. You are basically adding a same document twice.
Solr will update/overwrite the document. updated is basically delete and add.
As the second document you added with the same id does not have the price field, it won't be added and you wont find it the index.
you would need to have all the fields changed and unchanged when you are adding back the document.
doc2.addField("price", new Float(10)); // should add it back to the document