I'm trying to develop an app that retrive all documents inserted in a certain period.
This is my actual sample code:
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoDatabase database = mongoClient.getDatabase("eam");
MongoCollection<Document> collection = database.getCollection("coll");
List<Document> docsList = new ArrayList<>();
LocalDateTime initDate = LocalDateTime.now();
LocalDateTime endDate = initDate.plusSeconds(5);
int i = 0;
while (LocalDateTime.now().isBefore(endDate)) {
Document doc = new Document("id", i)
.append("name objy", "Obj " + i)
.append("timeStamp", LocalDateTime.now());
docsList.add(doc);
i++;
}
collection.insertMany(docsList);
MongoCursor<Document> cursor = collection.find(new Document("timestamp", new Document("$gte", endDate.minusSeconds(3)).append("$lte", endDate.minusSeconds(2)))).iterator();
try {
while (cursor.hasNext()) {
System.out.println(cursor.next().toJson());
}
} finally {
cursor.close();
}
As #Valijo, I modified my code to filter by gte and lte but now It doesn't return anything!
Why?
Take a look at https://docs.mongodb.com/manual/reference/method/Date/ if you don't want to work with timestamps
$in checks if timestamp is equals to one of the values inside the $in: https://docs.mongodb.com/manual/reference/operator/query/in/
But you need a between, this code should work for you:
db.yourcollection.find({$gte: {'timestamp': min}, $lte: {'timestamp': max}})
please mind: the above code is for mongo shell, but you should be able to "translate" it to your needed syntax
EDIT: also mind that mongodbs time is always UTC
$in selects exact values as given array.
So, you need to keep the exact timestamp reference (with 1 ms precision)
The problem is here:
LocalDateTime initDate = LocalDateTime.now();
LocalDateTime endDate = initDate.plusSeconds(5);
int i = 0;
while (LocalDateTime.now().isBefore(endDate)) {
Document doc = new Document("id", i)
.append("name objy", "Obj " + i)
.append("timeStamp", LocalDateTime.now()); //<-- The timestamp ms may differ from initDate ms
docsList.add(doc);
i++;
}
Solution 1: While inserting documents, use:
initDate.plusSeconds(i)
And then your query will return what you expect
Solution 2: (You may translate to your programming language)
Keep timeStamp references and then search them
var date1 = new Date(1537457334015); //Thursday, 20 September 2018 15:28:54.015
var date2 = new Date(1537457335014); //Thursday, 20 September 2018 15:28:55.014
var date3 = new Date(1537457336015); //Thursday, 20 September 2018 15:28:56.015 1 sec 1 ms
var date4 = new Date(1537457336025); //Thursday, 20 September 2018 15:28:56.025 2 sec 11 ms
var date2Plus1Sec = new Date( date2.getTime() + 1000 );
//db.coll.remove({})
db.coll.insert([
{
"timeStamp" : date1
},
{
"timeStamp" : date2
},
{
"timeStamp" : date3
},
{
"timeStamp" : date4
}
])
db.coll.find({"timeStamp" :{$in: [date1, date2, date2Plus1Sec ]} } ).pretty();
Result:
/* 1 */
{
"_id" : ObjectId("5ba3bea3ba135b198e17ec2d"),
"timeStamp" : ISODate("2018-09-20T15:28:54.015Z")
}
/* 2 */
{
"_id" : ObjectId("5ba3bea3ba135b198e17ec2e"),
"timeStamp" : ISODate("2018-09-20T15:28:55.014Z")
}
So Thursday, 20 September 2018 15:28:56.014 not exists in database
Solution 3: Don't use exact value match and use $gte and $lte operators to search timeStamp range
Related
I am trying to use mongo's Java driver to read through a collection and only pull back documents with a field that is a range of values. An example of this would be if I had data like
{ "name" : "foo", "Color" : "white", "Date" : 20171116 }
{ "name" : "bar", "Color" : "black", "Date" : 20171115 }
{ "name" : "Jeff", "Color" : "purple", "Date" : 20171114 }
{ "name" : "John", "Color" : "blue", "Date" : 20171015 }
I would want to begin on 20171114 and end on 20171116 so I would do something like
DateFormat df = new SimpleDateFormat("yyyyMMdd");
String begin = "20171114";
String end = "20171116";
Date startDate;
Date endDate;
Then I would need to convert the strings to a date and use a cursor like
try {
startDate = df.parse(startDateString);
endDate = df.parse(endDateString);
BasicDBObject data = new BasicDBObject();
data.put("Date", new BasicDBObject( new BasicDBOject( "$gte", startDate).append("$lte", endDate)));
} catch(ParseException e){
e.printStackTrace
}
However when I do this it returns nothing.
Answer:
I was trying to compare a number to a date which doesn't work so I converted my begin & end string to integers by doing
Integer beginDate = Integer.valueOf(begin)
Integer endDate = Integer.valueOf(end)
and it worked.
I think you have saved values of Date as numbers. Please check your code once how you are saving and please let us know.
Considering that please try below by passing long values as
try {
Long startDate = 20171114L;
Long endDate = 20171116L;
BasicDBObject data = new BasicDBObject();
data.put("Date", new BasicDBObject( new BasicDBObject( "$gte", startDate).append("$lte", endDate)));
} catch(ParseException e){
e.printStackTrace
}
I am trying search through big data collection of objects (1 000 000 000 elements).
Sample element looks like this:
Document{{_id=588e6f317367651f34a06c2c, busId=34, time=1262305558050, createdDate=Sun Jan 29 23:39:42 CET 2017}}
there are busIds from 0 to 300 and time increment about 30 milisecond on each record begins from
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
long startDate = sdf.parse("2010.01.01 00:00:00").getTime();
Now I am looking for all data with this query:
BasicDBObject gtQuery = new BasicDBObject();
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
obj.add(new BasicDBObject("busId", vehicleId));
obj.add(new BasicDBObject("time", new BasicDBObject("$gt", startDate.getTime()).append("$lt", endDate.getTime())));
gtQuery.put("$and", obj);
System.out.println(gtQuery.toString());
FindIterable<Document> curs = collection.find(gtQuery);
gtQuery output:
{ "$and" : [ { "busId" : "34"} , { "time" : { "$gt" : 1262304705000 , "$lt" : 1262308305000}}]}
Query is working but in this way it iterates over whole 1 000 000 000 elements in collection.
Is there any way to do it faster?
Try creating a compound index on busId and time as suggested by #ares
I am new to Java and to Google Script Editor. I have a custom CRM spreadsheet in google sheets, and would like to set up reminder emails based on regularly scheduled follow-up dates. I'm having trouble with the code. I think the trouble may be due to the fact that I'm trying to compare a date to a string, but I can't figure out how to get it to work.
The goal is to send off an email when the date for follow-up matches today's date. The date for follow-up is calculated based on a formula.
Even when the log reads:
[16-07-28 13:38:06:549 PDT] Date is Thu Jul 28 2016 00:00:00 GMT-0700 (PDT)
[16-07-28 13:38:06:549 PDT] Today is Thu Jul 28 2016 00:00:00 GMT-0700 (PDT)
My If statement if (date == todayFull) doesn't work. Here's the code:
function sendEmails() {
var ss = SpreadsheetApp.openById("number");
var sheet = ss.getSheetByName("Script");
var startRow = 2; // First row of data to process
var lastRow = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
// Fetch the range of cells
var dataRange = sheet.getRange(2, 1, lastRow, lastCol);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var date = row[32];
var todayFull = new Date();
todayFull.setHours(0);
todayFull.setMinutes(0);
todayFull.setSeconds(0);
Logger.log("Date is "+date);
Logger.log("Today is "+todayFull);
if (date == todayFull) {
Logger.log("This is a test. The Date is Today");
// var emailAddress = row[28]; // Email column
// var groupName = row[3]; // Group Name column
// var subject = "Follow up with this group right now!";
// MailApp.sendEmail(emailAddress, subject, groupName);
};
};
}
Thanks for the help. The first answer ended up working most of the way. Using .getDate() helped, but I also had to add arguments for month and year. Here's the code I ended up with:
function sendEmails() {
var ss = SpreadsheetApp.openById("");
var sheet = ss.getSheetByName("");
var startRow = 4; // First row of data to process
var lastRow = sheet.getLastRow(); //Get the last row of data to be processed
var lastCol = sheet.getLastColumn();
var dataRange = sheet.getRange(2, 1, lastRow-3, lastCol);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var date2 = new Date(row[24]); // creates a new Date (date in string) object
var todayFull2 = new Date(); // creates a new Date (now) object
if (date2.getDate() == todayFull2.getDate() && date2.getMonth() == todayFull2.getMonth() && date2.getYear() == todayFull2.getYear()) {
etc
You're comparing two different data types:
var date = row[32]; // reads in a String object
var todayFull = new Date(); // creates a new Date (now) object
...
if (date == todayFull) { // compares Date with String
...
}
You might be better off creating the Date object when you read the value from your Sheet, and then comparing the actual dates in milliseconds (at time 00:00:00:00 of given date) of those Date objects, as you appear to be intending to do:
var date = new Date(row[32]); // creates a new Date (date in string) object
var todayFull = new Date(); // creates a new Date (now) object
todayFull.setHours(0,0,0,0) // sets time to midnight of current day
...
// compare Date with Date
if (date.getTime() == todayFull.getTime()) {
...
}
See MDN's excellent documentation on Javascript's Date.
I have Kendo grid with server filtering enable , if I click on filtering the date column , the server is receiving the date value as standard one like below
Tue May 03 2016 00:00:00 GMT+0400 (Arabian Standard Time)
I know how to change the date value on update , like below
parameterMap: function(data, type) {
if (type !== "read" && data.models) {
//return {models: kendo.stringify(options.models)};
var d = new Date( data.models[0].joinDate );
data.models[0].joinDate = kendo.toString(new Date(d), "yyyy-MM-dd");
console.log("date is:"+data.models[0].joinDate);
// here the server is receiving the join date as yyyy-MM-dd
return data;
}
}
else
{
// it is showing an error if i do like that
// var d = new Date( data.models[0].joinDate );
// data.models[0].joinDate = kendo.toString(new Date(d), "yyyy-MM-dd");
return data;
}
now my question is what is the function that fires if I click on filter button of the grid which in there I can parse the date to sql format before sending to server . I have tried to do it in read function as mentioned above but it is showing an error .
I think I solve it after long time searching , and this answer for someone who is searching like me .
In order to change the filter field value from standard date-time format to sql format before sending to the server , we need to change the value of that field in filter configuration object of the datasource for the grid .
in order to get the filter configuration object , we can get inside transport.parameterMap like below
parameterMap: function(data, type) {
if (type !== "read" && data.models) {
//return {models: kendo.stringify(options.models)};
var d = new Date( data.models[0].joinDate );
data.models[0].joinDate = kendo.toString(new Date(d), "yyyy-MM-dd");
console.log("joinDate in sql frmat for any update on grid:"+data.models[0].joinDate);
return data;
}
else
{
// get currently applied filters from the Grid is data.filter.
var currFilterObj = data.filter;
var currentFilters = currFilterObj ? currFilterObj.filters : [];
if (currentFilters && currentFilters.length > 0) {
for (var i = 0; i < currentFilters.length; i++) {
if (currentFilters[i].field == "joinDate")
{
var d = new Date( currentFilters[i].value );
currentFilters[i].value = kendo.toString(new Date(d), "yyyy-MM-dd");
console.log("Now joinDate value is in sql format "+currentFilters[i].value);
}
}
}
return data;
}
I am using spring data with mongodb to create an application.
I have this object:
public class Room {
private String name;
private List<Date> occupied;
}
I want using mongodbTemplate preferably to get the list of room that are not occupied for a date range.
So for example if i have a start date 10/10/2014 and end date 15/10/2014 I want to get the list of rooms that do not have in the list occupied the dates 10,11,12,13,14,15 for October 2014.
Does anyone have any idea on this?
Update:
I have found a way to do this by using this query:
query.addCriteria(Criteria.where("occupiedDates")
.ne(from).andOperator(
Criteria.where("occupiedDates").ne(to))
);
the problem is that I can not dynamically add the andOperator.
I would prefer inside the criteria to add a list of dates if possible.
An example document is (only one record exists in mongo this one) :
Room(bedcount=1, bedtype1=1, bedtype2=0, bedtype3=0, bedtype4=0,
filetype=null, noofrooms=0, occupancy=0, photo=null, rateid=1,
roomname=null, roomno=888, status=null,
roomTypeID=26060747427845848211948325568, occupiedDates=[Sun Aug 10
00:00:00 EEST 2014, Mon Aug 11 00:00:00 EEST 2014, Tue Aug 12 00:00:00
EEST 2014, Wed Aug 13 00:00:00 EEST 2014], attributes={})
And this is the code of how the wyeru is built:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
Date to = null;
Date from = null;
try {
to = dateFormat.parse("12-08-2014 00:00:00");
from = dateFormat.parse("10-08-2014 00:00:00");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DBObject c1 = new BasicDBObject("occupied", null);
DBObject c2 = BasicDBObjectBuilder.start()
.push("occupied").push("$not")
.push("$elemMatch").add("$gte", from).add("$lte", to).get();
Criteria c = Criteria.where("$or").is(Arrays.asList(c1, c2));
Query query = new Query().addCriteria(c);
List<Room> rooms = mongoTemplate.find(query, Room.class);
This query is sent to mongodb
{ "$or" : [
{ "occupied" : null } ,
{ "occupied" :
{ "$not" :
{ "$elemMatch" :
{ "$gte" : { "$date" : "2014-08-09T21:00:00.000Z"} ,
"$lte" : { "$date" : "2014-08-11T21:00:00.000Z"}
}
}
}
}
]}
from this we understand that the query should return nothing. but it returns me 1 row.
As the requirements I understood eventually, you want to fetch all documents in which
none of elements of occupied falls into the specified date range.
Complete on mongo shell:
db.b.find({
$or : [{
occupied : null
}, {
occupied : {
$not : {
$elemMatch : {
$gte : start,
$lte : end
}
}
}
}]
}).pretty();
Then translate to Java code as below:
// Because "Criteria" has a bug when invoking its method "elemMatch",
// so I build the criteria by the driver directly, almost.
DBObject c1 = new BasicDBObject("occupied", null);
DBObject c2 = BasicDBObjectBuilder.start().push("occupied").push("$not").
push("$elemMatch").add("$gte", start).add("$lte", end).get();
Criteria c = where("$or").is(Arrays.asList(c1, c2));
Query query = new Query().addCriteria(c);
List<Room> rooms = mongoTemplate.find(query, Room.class);
Analysis routing
According to your question, suppose there are some resources as below:
occupied = [d1, d2, d3, d4, d5]; // for easier representation, suppose elements are in ascending order
range = [start, end];
So, you want to return every document if its data satisfy one of the following criteria after sorting in ascending order:
start, end, d1, d2, d3, d4, d5 // equivalent to: min(occupied) > end
d1, d2, d3, d4, d5, start, end // equivalent to: max(occupied) < start
If elements are stored in order in occupied, it is easy to fetch the minimum and maximum value.
But you don't mention it, so I suppose essentially they are not in order.
Unfortunately, there is no operator to get minimum or maximum value from an array in standard query.
But according to the feature of array field in comparison of standard query,
matching will return true if at least one element or itself satisfying the criteria;
return false only all fail the criteria.
It's lucky to find that min(occupied) > end is equivalent to NOT (at least one element <= end), which is the key point to achieve by following method.
Fulfill on mongo shell:
db.b.find({
$or: [{
occupied: {
$not: {
$lte: end
}
}
}, {
occupied: {
$not: {
$gte: start
}
}
}]
}). pretty();
Then translate to Java code like this:
Criteria c = new Criteria().orOperator(where("occupied").not().lte(end),
where("occupied").not().gte(start));
Query query = new Query().addCriteria(c);
List<Room> rooms = mongoTemplate.find(query, Room.class);