Object
YALTools::YaDocs is designed to process huge amount of documents through the CouchDB REST API.
For the performance, the page variable is used to calculate skip and limit query variables.
If there are seven documents on the example db and the limit query option is set to three, then to get the all documents, the uri will be generated in the following manner;
/example/_all_docs?limit=3&skip=0 => {..,"rows":[{"_id":..},{"_id":..},{"_id":..}]}
/example/_all_docs?limit=3&skip=3 => {..,"rows":[{"_id":..},{"_id":..},{"_id":..}]}
/example/_all_docs?limit=3&skip=6 => {..,"rows":[{"_id":..}]}
Corresponding code is the following;
view = YALTools::YaAllDocs.new(@couch, "example")
q_opts = { "include_docs" => "true" } ## or some query options
view.each(q_opts, 0, 3) do |resset, skip, page, max_page, max_rows|
resset.each do |row|
...
end
end
The number of page starts from one and the max_page variable will be set to three.
Please refer the unittest/ut.yalt.yaview.rb file about available query options.
YALTools::YaDocs is an abstract class.
Please use YALTools::YaViewDocs and YALTools::YaAllDocs classes for acutual use.
yields [rows, skip, page, max_page, max_rows].
The query_options must be proper view query options,
# File yalt/yaview.rb, line 132
132: def each(query_options={}, start_page=0, limit=15) # :yields: rows, skip, page, max_page, max_rows
133: pages(@default_query_options.merge(query_options), start_page, limit, true, false) do |rows, skip, page, max_page ,max_rows|
134: yield [rows, skip, page, max_page ,max_rows]
135: end
136: end
yields [rows, skip, page, max_page, max_rows] with attachment documents. It might be too slow.
The query_options must be proper view query options,
# File yalt/yaview.rb, line 143
143: def each_with_attachments(query_options={}, start_page=0, limit=15) # :yields: rows, skip, page, max_page, max_rows
144: pages(@default_query_options.merge(query_options), start_page, limit, true, true) do |rows, skip, page, max_page ,max_rows|
145: yield [rows, skip, page, max_page ,max_rows]
146: end
147: end
yields [rows, page, next_page_flag]
an instance of YALTools::YaJsonRows.
the number of the current page.
true if next page exists.
# File yalt/yaview.rb, line 98
98: def get_all(query_options={}, current_page=1, limit=15) # :yields: rows,page,next_page_flag
99: opts = @default_query_options.merge(query_options)
100: page = current_page.to_i
101: page = 1 if page < 1
102: while true
103: opts["skip"] = limit * (page - 1)
104: opts["limit"] = limit + 1
105: uri = gen_view_uri(opts)
106: $stderr.puts "[debug] get_all() uri=#{uri}" if @debug
107:
108: rows = YALTools::YaJsonRows.new(@couch, @dbname)
109: json = @couch.get(uri)
110: i=0
111: next_row = nil
112: next_page_flag = false
113: json.has_key?("rows") and yield_rows(json["rows"]) do |r|
114: if i == limit
115: next_page_flag = true
116: else
117: rows << r
118: end
119: i += 1
120: end
121: break if rows.length == 0
122: yield [rows, page, next_page_flag]
123: break if next_page_flag == false
124: page += 1
125: end
126: end
options must be proper view query option values.
options = {"group" => true}
max_numrows(options) #=> 30
reduce:
_count | group | gropu_numrows | startkey/endkey/key | reduce | skip | limit |
--------+-------+---------------+---------------------+--------+------+-------+
yes | on | on | off | true* | del | del |
yes | on | on | on | true* | del | del |
yes | off | off | on | true | del | del |
yes | off | off | off | false | del | 0 |
no | off | off | off | false | del | 0 |
no | off | off | on | false | del | del |
# File yalt/yaview.rb, line 66
66: def max_numrows(options={})
67: opts = {}
68:
69: if options.has_key?("startkey") or options.has_key?("endkey") or options.has_key?("key")
70: opts["startkey"] = options["startkey"] if options.has_key?("startkey") and not options["startkey"] == nil
71: opts["endkey"] = options["endkey"] if options.has_key?("endkey") and not options["endkey"] == nil
72: opts["key"] = options["key"] if options.has_key?("key") and not options["key"] == nil
73: else
74: opts["reduce"] = "false"
75: opts["limit"] = "0"
76: end
77: if options.has_key?("group") and options["group"].to_s == "true"
78: opts["group"] = "true"
79: opts["group_numrows"] = "true"
80:
81: opts.delete("reduce")
82: opts.delete("limit")
83: end
84: opts.delete("include_docs")
85:
86: uri = gen_view_uri(opts)
87: $stderr.puts "[debug] max_numrows() uri=#{uri}" if @debug
88:
89: return total_numrows(@couch.get(uri), opts)
90: end
returns [rows, skip, page, max_page, max_rows]. It is same as the yielded variables at YaDocs::each.
It returns just a result specified by the page variable.
# File yalt/yaview.rb, line 154
154: def page(query_options={}, page_num=0, limit=15)
155: return pages(@default_query_options.merge(query_options), page_num, limit, false, false)
156: end
returns the uri from baseuri and opts.
gen_uri_with_options("/foo/path", {"k"=>"v","k2"=>"v2"}) #=> "/foo/path?k=v&k2=v2"
# File yalt/yaview.rb, line 290
290: def gen_uri_with_options(baseuri, opts)
291: uri = baseuri
292: uri += "?" if uri !~ /\?$|\&$/
293: tmp_list = []
294: opts.kind_of?(Hash) and opts.each do |k,v|
295: next if v == nil or (v.respond_to?("empty?") and v.empty?)
296: tmp_list << "#{k}=#{v}"
297: end
298: uri += tmp_list.join("&")
299: return uri
300: end
returns uri string, such as “/example/_design/all/_view/type?reduce=false&include_docs=true“
# File yalt/yaview.rb, line 239
239: def gen_view_uri(opts={})
240: uri = format("/%s/_all_docs", @dbname)
241:
242: msg = { "uri" => uri } and $stderr.puts msg.to_json if @debug
243:
244: return gen_uri_with_options(uri, opts)
245: end
returns Hash object of the given document
doc == { “_id”=>“xxx”, “key1”=>“val1”, “key2”=>“val2” }
# File yalt/yaview.rb, line 230
230: def get_page_with_attachment(doc)
231: $stderr.puts "[debug] get_page_with_attachment(doc=#{doc})" if @debug
232: id = doc["_id"] if doc.has_key?("_id")
233: uri = "/#{@dbname}/#{id}?attachments=true"
234: $stderr.puts "[debug] get_page_with_attachment() uri=#{uri}" if @debug
235: return @couch.get(uri)
236: end
returns or yield YALTools::YaJsonRows instance and some informational variables.
# File yalt/yaview.rb, line 163
163: def pages(options={}, page=0, limit=15, do_iterate=false, with_attachments=false)
164: $stderr.puts "[debug] pages(options=#{options}, page=#{page}, limit=#{limit}, do_iterate=#{do_iterate})" if @debug
165: opts = options.dup
166: max_rows = max_numrows(opts)
167: $stderr.puts "[debug] pages() max_rows=#{max_rows}" if @debug
168:
169: opts["limit"] = limit
170: if options.has_key?("group") and options["group"].to_s == "true"
171: opts.delete("reduce")
172: opts.delete("include_docs")
173: else
174: opts.delete("group")
175: opts["reduce"] = "false"
176: end
177:
178: ## type 1
179: yield_skip_page(limit, max_rows, page) do |i_limit, skip, current_page, max_page|
180: opts["skip"] = skip
181: opts["limit"] = i_limit
182: uri = gen_view_uri(opts)
183: $stderr.puts "[debug] pages() uri=#{uri}" if @debug
184:
185: resset = YALTools::YaJsonRows.new(@couch, @dbname)
186: json = @couch.get(uri)
187: json.has_key?("rows") and yield_rows(json["rows"]) do |doc|
188: if with_attachments and doc.has_key?("_attachments")
189: resset << get_page_with_attachment(doc)
190: else
191: resset << doc
192: end
193: end
194: if do_iterate
195: yield [resset, skip, current_page, max_page ,max_rows]
196: else
197: return [resset, skip, current_page, max_page ,max_rows]
198: end
199: end
200:
201: ## type 2
202: yield_skip_page_r(limit, max_rows, page, opts) do |i_limit, skip, current_page, max_page, new_opts| new_opts["skip"] = skip new_opts["limit"] = i_limit uri = gen_view_uri(new_opts) $stderr.puts "[debug] pages() uri=#{uri}" if @debug resset = YALTools::YaJsonRows.new(@couch, @dbname) json = @couch.get(uri) json.has_key?("rows") and yield_rows(json["rows"]) do |doc| if with_attachments and doc.has_key?("_attachments") resset << get_page_with_attachment(doc) else resset << doc end end if do_iterate yield [resset.reverse, (max_rows - skip - i_limit), (max_page - current_page + 1), max_page ,max_rows] else return [resset.reverse, (max_rows - skip - i_limit), (max_page - current_page + 1), max_page ,max_rows] end end=end
203: end
returns the total number of results.
total_numrows(json) #=> 30
It accepts the following json data format;
{“total_rows“:11,“offset”:0,“rows”:[]}
{“rows”:[{“key”:null,“value”:10}]}
{“group_numrows“:“1”}
{“rows":} (if group_numrows is not implemented)
The “group_numrows“ is special case. Please see [github.com/YasuhiroABE/CouchDB-Group_NumRows].
# File yalt/yaview.rb, line 260
260: def total_numrows(json, opts={})
261: $stderr.puts "total_numrows(json=#{json}, opts=#{opts})" if @debug
262: ret = 0
263: if json.kind_of?(Hash)
264: if json.has_key?("total_rows")
265: ret = json["total_rows"].to_i
266: if json.has_key?("rows") and json["rows"].kind_of?(Array)
267: i = json["rows"].length
268: ret = i if i > 0
269: end
270: elsif json.has_key?("rows") and json["rows"][0].kind_of?(Hash) and json["rows"][0].has_key?("value")
271: if json["rows"].size == 1 and json["rows"][0].has_key?("key") and json["rows"][0]["key"] == nil
272: ret = json["rows"][0]["value"].to_i
273: elsif opts.has_key?("group_numrows") and opts["group_numrows"].to_s == "true"
274: ## if group_numrows is not implemented.
275: ret = json["rows"].size
276: end
277: elsif json.has_key?("group_numrows")
278: ret = json["group_numrows"].to_i
279: end
280: end
281:
282: $stderr.puts "[debug] total_numrows=#{ret}" if @debug
283: return ret
284: end
iterates each row of the rows array.
# File yalt/yaview.rb, line 392
392: def yield_rows(rows) # :yields: row
393: rows.respond_to?(:each) and rows.each do |row|
394: if row.has_key?("doc") and row["doc"].kind_of?(Hash)
395: ## if include_docs=true
396: yield row["doc"]
397: else
398: yield row
399: end
400: end
401: end
iterates skip and page parameters for a view query.
The max_page will be calculated in the following way.
+------------+-------+------------------+----------+
| total_rows | limit | total_rows/limit | max_page |
+------------+-------+------------------+----------+
| 10 | 4 | 2 | 3 |
+------------+-------+------------------+----------+
| 10 | 5 | 2 | 2 |
+------------+-------+------------------+----------+
| 10 | 6 | 1 | 2 |
+------------+-------+------------------+----------+
# File yalt/yaview.rb, line 316
316: def yield_skip_page(limit, total_rows, start_page=1) # :yields: limit, skip, page, max_page
317: max_page = (total_rows.to_f / limit.to_f).ceil
318:
319: page = start_page <= max_page ? start_page : max_page
320: page = 1 if page < 1 ## 'page' must be greater than one, even though max_page is zero.
321: skip = limit * (page - 1)
322:
323: while page <= max_page
324: if page == max_page
325: tmp_r = (total_rows % limit)
326: yield [tmp_r == 0 ? limit : tmp_r, skip,page,max_page]
327: else
328: yield [limit,skip,page,max_page]
329: end
330: skip = limit * page
331: page += 1
332: end
333: end
yield_skip_page_r is a reverse version of the yield_skip_page.
It is an experimental implementation.
start_page is from one to max_page, less than one will be rounded to one.
# File yalt/yaview.rb, line 341
341: def yield_skip_page_r(unit, total_rows, start_page=1, query_opts) # :yields: limit, skip, page, max_page, new_query_opts
342: opts = query_opts.dup
343: limit = unit
344:
345: # swaping +startkey+, +endkey+ and "descending" options.
346: case "#{opts.has_key?('startkey')}.#{opts.has_key?('endkey')}"
347: when "true.true"
348: opts["startkey"] = query_opts["endkey"]
349: opts["endkey"] = query_opts["startkey"]
350: when "true.false"
351: opts["endkey"] = opts["startkey"]
352: opts.delete("startkey")
353: when "false.true"
354: opts["startkey"] = opts["endkey"]
355: opts.delete("endkey")
356: end
357: if opts.has_key?("descending")
358: opts["descending"] = (opts["descending"].to_s == "true") ? "false" : "true"
359: else
360: opts["descending"] = "true"
361: end
362:
363: max_page = (total_rows.to_f / limit.to_f).ceil
364:
365: sanitized_start_page = start_page > 0 ? start_page : 1
366: page = (max_page - sanitized_start_page + 1)
367: page = 1 if page < 1 ## 'page' must be greater than one, even though max_page is zero.
368: skip = total_rows - (limit * (max_page - page + 1))
369: skip = total_rows if skip > total_rows
370: skip = 0 if skip < 0
371:
372: $stderr.puts "[debug] yield_skip_page_r() sanitized_start_page=#{sanitized_start_page},skip=#{skip},page=#{page}" if @debug
373:
374: while page >= 1
375: $stderr.puts "[debug] yield_skip_page_r() skip=#{skip},page=#{page},max_page=#{max_page}" if @debug
376: if skip == 0
377: tmp_limit = total_rows % limit
378: tmp_limit = limit if tmp_limit == 0
379: yield [tmp_limit, skip, page, max_page, opts]
380: else
381: yield [limit, skip, page, max_page, opts]
382: end
383: page -= 1
384: # skip = limit * (page - 1)
385: skip -= limit
386: skip = 0 if skip < 0
387: end
388: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.