Updating/destroying EmbeddedDocuments in MongoMapper - mongomapper

I can't seem to figure out how to update or destroy EmbeddedDocuments in MongoMapper. Through Googling I've seen different methods like delete_if {} and others, but none seem to work for me semantically. Is there anything built-in to MongoMapper to help with this?
class Schedule
include MongoMapper::Document
key :name, String
key :description, String
key :active, Boolean, :default => false
many :periods
validates_presence_of :name
def activate!
set({:active => true}, :active => false)
self.active = true
end
end
class Period
include MongoMapper::EmbeddedDocument
key :number, Integer
key :text, String
key :start, Time
key :finish, Time
embedded_in :schedule
before_validation :number!
validates_presence_of :number
validates_presence_of :text
validates_presence_of :start
validates_presence_of :finish
validates_format_of :start, :with => /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/
validates_format_of :finish, :with => /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/
def number!
unless self.number
number = schedule.periods.count + 1
end
end
end

The follow test shows examples on how to update and remove embedded documents in two ways:
(1) via Ruby using standard Array accessors and methods, and
(2) via Mongo (MongoMapper / MongoDB) for update and removal of embedded documents on the DB server
References:
http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-delete_if
http://mongomapper.com/documentation/plugins/modifiers.html#set
http://www.mongodb.org/display/DOCS/Updating#Updating-%24set
Note that Hash keys containing '.' require use of the old ( => ) syntax. Hope that this helps.
test/unit/period_test.rb
require 'test_helper'
def ppp(obj)
puts obj.inspect.gsub(/(, |\[)#/, "\\1\n #")
end
class PeriodTest < ActiveSupport::TestCase
def setup
Schedule.delete_all
#today = Time.now.midnight
end
test "update and remove embedded documents" do
schedule = Schedule.create(name: 'George')
assert_equal(1, Schedule.count)
schedule.periods << Period.new(number: 1, text: 'period 1', start: #today + 8.hours, finish: #today + 9.hours)
schedule.periods << Period.new(number: 2, text: 'period 2', start: #today + 9.hours, finish: #today + 10.hours)
schedule.periods << Period.new(number: 3, text: 'period 3', start: #today + 10.hours, finish: #today + 11.hours)
schedule.periods.last.finish = #today + 12.hours #update in Ruby
schedule.save
assert_equal(1, Schedule.count)
puts "schedule with three periods --------"
ppp Schedule.first
schedule.periods.delete_if {|period| period.text == 'period 2'} #remove in Ruby
schedule.save
puts "schedule after removing period 2 in Ruby --------"
ppp Schedule.first
Schedule.set( {name: 'George', 'periods.text' => 'period 1'}, {'periods.$.finish' => #today + 10.hours} ) #update embedded document in MongoDB
puts "schedule after updatting period 1 via Mongo --------"
ppp Schedule.first
Schedule.pull( {name: 'George'}, { periods: { text: 'period 1'} } ) #remove embedded document in MongoDB
puts "schedule after pulling period 1 via Mongo --------"
ppp Schedule.first
end
end
output
Run options: --name=test_update_and_remove_embedded_documents
# Running tests:
schedule with three periods --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000002'), finish: Fri, 06 Jul 2012 13:00:00 UTC +00:00, number: 1, start: Fri, 06 Jul 2012 12:00:00 UTC +00:00, text: "period 1">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000003'), finish: Fri, 06 Jul 2012 14:00:00 UTC +00:00, number: 2, start: Fri, 06 Jul 2012 13:00:00 UTC +00:00, text: "period 2">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
schedule after removing period 2 in Ruby --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000002'), finish: Fri, 06 Jul 2012 13:00:00 UTC +00:00, number: 1, start: Fri, 06 Jul 2012 12:00:00 UTC +00:00, text: "period 1">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
schedule after updatting period 1 via Mongo --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000002'), finish: Fri, 06 Jul 2012 14:00:00 UTC +00:00, number: 1, start: Fri, 06 Jul 2012 12:00:00 UTC +00:00, text: "period 1">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
schedule after pulling period 1 via Mongo --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
.
Finished tests in 0.038952s, 25.6726 tests/s, 51.3452 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips

Related

postgresql convert 'Thu Jul 02 13:36:17 UTC 2020' to timestamp

I have a string that I need to insert into a table as a timestamp.
'Thu Jul 02 13:36:17 UTC 2020'
Without UTC the following conversion works
SELECT to_timestamp('Thu Jul 02 13:36:17 2020', 'Dy Mon dd HH24:MI:SS yyyy');
How can I convert the timestamp with the UTC portion?
Any help would be greatly appreciated!
Database Type: PostgreSQL
Table Data Type: timestamp (this can change if needed)
If it's always going to be UTC, then you can use:
> select to_timestamp(
'Thu Jul 02 13:36:17 UTC 2020',
'Dy Mon DD HH24:MI:SS UTC YYYY'
);

find results not matching date in selector

A Meteor client Template returns mongodb cursor. The collection has 3 documents which contain date field. I expected the find to return 3 documents, but it only gave one the date of which is Mon Aug 08 2016 00:00:00 GMT+1000 (AEST).
Why is that and how can I get the 3 documents? Thanks
"date" : ISODate("2016-08-08T14:00:00Z"),
"date" : ISODate("2016-08-08T14:00:00Z"),
"date" : ISODate("2016-08-07T14:00:00Z"),
console.log(start); //=> Sun Aug 07 2016 00:00:00 GMT+1000 (AEST)
console.log(end); //=> Mon Aug 08 2016 00:00:00 GMT+1000 (AEST)
console.log(myCol.find({date: {$gte: start, $lte: end}}).fetch()); // expected 3 not just 1
the code below shows how the date was before inserting in the collection.
const date = cheerioObj(this).next().html().trim();
const dArr = date.split('/');
const dObj = new Date(parseInt(dArr[2]), parseInt(dArr[1]) - 1, parseInt(dArr[0]));
EDIT: Sorry, it's late.
It may be to do with your .fetch() method. Try iterating the cursor instead:
var myArray = db.users.find({...}).toArray();
Then access each in a for loop.

Rails 4, Heroku, Comparing times not working

Using Heroku, I am trying to compare a saved times (open and close) of a place to the current time to determine what to output.
Code:
def get_place_search_display(open_time, close_time)
open_time_formatted = open_time.strftime('%l:%M %p') if !open_time.nil?
close_time_formatted = close_time.strftime('%l:%M %p') if !close_time.nil?
current_time = Time.current #.strftime('%l:%M %p')
if open_time.nil? || close_time.nil?
"Closed today"
elsif current_time < open_time
"Opens at #{open_time} until #{close_time}"
elsif current_time >= open_time && current_time <= close_time
"Open #{open_time} - #{close_time}"
elsif current_time > close_time
"Closed at #{close_time} today"
else
"Open until #{close_time} today"
end
end
Example returned values:
Open time: 7:00 AM
Close time: 8:45 PM, 2000-01-01 20:45:00 UTC
Current time: 6:35 PM, 2014-09-07 18:35:36 -0700
Returns: "Closed at 2000-01-01 20:45:00 UTC today"
Any ideas what the comparison isn't working using this logic?
Looking at the term "today" in your output string, and also the '%l:%M %p' in your time formatting method, I assume you are trying to compare Time objects without Date info
However in Ruby, Time object always comes with date. But you can achieve that by converting them into the same day before comparing them.
a = Time.current
=> Mon, 08 Sep 2014 02:30:44 UTC +00:00
b = Time.current.months_ago(1)
=> Fri, 08 Aug 2014 02:30:59 UTC +00:00
a > b
=> true
a2 = a.change(day:1, month:1, year:2000)
=> Sat, 01 Jan 2000 02:30:44 UTC +00:00
b2 = b.change(day:1, month:1, year:2000)
=> Sat, 01 Jan 2000 02:30:59 UTC +00:00
a2 > b2
=> false
Hope it helps.

MongoDB row index limit query like SQL

I would like to retrieve a list that contains an specified record under some conditions and only retrieve a number of records before and a number of records after that record. Are there any solutions?
For example, I have a MongoDB schema { id, date, section }
Data set:
100, 26 Aug 2014 11:00, A
110, 26 Aug 2014 11:01, A
140, 26 Aug 2014 12:00, A
141, 27 Aug 2014 12:00, B
200, 30 Aug 2014 11:00, A
210, 01 Sep 2014 11:01, B
290, 02 Sep 2014 12:00, A
300, 26 Sep 2014 12:00, A
301, 27 Oct 2014 12:00, B
302, 30 Oct 2014 11:23, A
410, 01 Oct 2014 15:01, B
590, 02 Oct 2014 12:00, A
600, 26 Nov 2014 00:00, A
I would like to get a list, which contains an unique id = 300 and 3 records before and 3 records after that record with id = 300, sorted by date under section A.
The output:
140, 26 Aug 2014 12:00, A
200, 30 Aug 2014 11:00, A
290, 02 Sep 2014 12:00, A
300, 26 Sep 2014 12:00, A <-- middle
302, 30 Oct 2014 11:23, A
590, 02 Oct 2014 12:00, A
600, 26 Nov 2014 00:00, A
I have a stupid approach:
get the date (let say it's 26 Sept 2014 12:00) of the specified id = 300 with section A
set a query to find records that the date is greater than and equal to 26 Sept 2014 12:00 ordered by date, limited by 3 records.
set a query to find records that the date is less than 26 Sept 2014 12:00 ordered by date, limited by 3 records.
combine two lists.
Is there any better approaches to just retrieve this kind of list in a query or in better performance? Thank you.
Let's your schema name be USER. You could use below mongo db query to fetch the result
$sort function :
1 represents ascending
-1 represents descending
Refer documentation : $Sort Documentation
Query will be :
db.user.aggregate({$match : { "id" : 300}},{$sort : {"date": 1 }},{$skip : 0},{$limit : 10});
$skip value will be your limit value after first query
db.user.aggregate({$match : { "id" : 300}},{$sort : {"date": 1 }},{$skip : 10},{$limit : 10});
Refer Documentation : Aggregation Documentation
$skip and $limit in aggregation framework
Here is a good example of using skip and limit which should help you achieve the SELECT TOP X or LIMIT X
Note: I'm assuming you want to use the aggregate framework based on the tagging of this question.
I believe this should do it
x = 300;
db.user.aggregate({$match : { "id" : {$lte: x+10,$gte: x-10 }},{$sort : {"date": 1 }}});

IndexedDB with range queries

I would like to find which date ranges overlaps another date range in IndexedDB.
Something like the following query:
SELECT * FROM events
WHERE (periodStart >= start AND periodStart < end)
OR (start >= periodStart AND start <= periodEnd)
Events looks like the following object:
[{
title: 'foo',
start: 'Tue Oct 29 2013 10:19:52 GMT-0400 (EDT)',
end: 'Tue Oct 29 2013 13:19:52 GMT-0400 (EDT)'
},
{
title: 'bar',
start: 'Tue Oct 30 2013 00:00:00 GMT-0400 (EDT)',
end: 'Tue Oct 31 2013 00:00:00 GMT-0400 (EDT)'
}]
To my knowledge, no ability to do unions in indexeddb (the OR).
So, as that kinda sucks, here is a half thought out solution that maybe puts you on the course: something like find the min of the set, and the max of the set, and then a query descending and a query ascending but just get the first record from each cursor, and then, something.