ruby_mongo_x 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9eaedb3e5a9b24803714ebeecbb8b2e1bb5116724da0ae0ef639127372403531
4
+ data.tar.gz: 91bd5334eaf9309e714ada4c27b1d427794880ca206e30743c2be253af52bf22
5
+ SHA512:
6
+ metadata.gz: 109a0d54f4e697f9aa41caf0f810e6952020926fd75f467cf3734bfc974aca81e719f98196f278d289ff94ed568fc073261625f561cd46b32820bde4892366c7
7
+ data.tar.gz: 1241abab507078eb3b1b43527a48e12dba103eb1c99b069022250d7874914804f547d90d68d88d20d6a1391392337c8cf926885598c1a3325a74ec0ba4636c75
@@ -0,0 +1,7 @@
1
+ module Helpers
2
+ module Loggable
3
+ def log_debug(message)
4
+ print "[#{self.class.name}] #{message} "
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,168 @@
1
+ require 'mongo'
2
+ require 'concurrent'
3
+ require_relative './helpers/loggable'
4
+
5
+ class RubyMongoX
6
+ include ::Helpers::Loggable
7
+
8
+ def self.build(collection_name, shards, max_count_per_shard)
9
+ new(collection_name, shards, max_count_per_shard)
10
+ end
11
+
12
+ def initialize(collection_name, shards, max_count_per_shard)
13
+ @max_count_per_shard = max_count_per_shard
14
+ @mongo_clients = {}
15
+
16
+ threads = []
17
+
18
+ options = {}
19
+
20
+ shards.each_with_index do |shard, idx|
21
+ threads << Thread.new do
22
+ log_debug "\t Connecting to shard #{shard} ...\n"
23
+ begin
24
+ @mongo_clients[idx.to_s] = ::Mongo::Client.new(shard, options)
25
+ rescue Mongo::Error::SocketError => e
26
+ log_debug "\t SocketError: #{e.message}...\n"
27
+ log_debug "\t SocketError: Stopped trying to connect to shard #{shard}... FAIL!\n"
28
+ rescue Mongo::Error::NoSRVRecords => e
29
+ log_debug "\t NoSRVRecords: #{e.message}...\n"
30
+ log_debug "\t NoSRVRecords: Retrying connect to shard #{shard}...\n"
31
+ sleep 1
32
+ retry
33
+ rescue Mongo::Error::SocketTimeoutError => e
34
+ log_debug "\t SocketTimeoutError: #{e.message}...\n"
35
+ log_debug "\t SocketTimeoutError: Retrying connect to shard #{shard}...\n"
36
+ sleep 1
37
+ retry
38
+ end
39
+ log_debug "\t Connected to shard #{shard} --> OK\n"
40
+ end
41
+ end
42
+
43
+ threads.each(&:join)
44
+ @collection_name = collection_name
45
+ end
46
+
47
+ def get_collection(key)
48
+ shard_idx = get_shard_index(key)
49
+ unless @mongo_clients[shard_idx.to_s].nil?
50
+ return @mongo_clients[shard_idx.to_s][@collection_name.to_sym]
51
+ else
52
+ raise StandardError.new("No Mongo shard for shard index: #{shard_idx} !!!")
53
+ end
54
+ end
55
+
56
+ # def ensure_indices(collection_name, index_definitions)
57
+ # @mongo_clients.each do |e|
58
+ # mongo_client = e[1]
59
+ # collection = mongo_client[collection_name.to_sym]
60
+ # mongo_user = collection.client.cluster.servers.first.options["user"]
61
+
62
+ # log_debug "\tEnsuring index: #{index_definitions} on #{collection_name} (#{mongo_user})... "
63
+ # mongo_client[collection_name.to_sym].indexes.create_many(index_definitions)
64
+ # log_debug " OK\n"
65
+ # end
66
+ # end
67
+
68
+ def get_shard_index(key)
69
+ ((key.to_i - 1).to_f / @max_count_per_shard).to_i
70
+ end
71
+
72
+ def find(query)
73
+ log_debug "\t Query: #{query.to_json}\n"
74
+ promises = @mongo_clients.map do |mongo_client_item|
75
+ mongo_client = mongo_client_item[1]
76
+ Concurrent::Promise.execute do
77
+ fetch_data_from_shard(mongo_client, query)
78
+ end
79
+ end
80
+ results = promises.map { |promise| promise.value[:results] }
81
+ merged_results = results.flatten
82
+ merged_results
83
+ end
84
+
85
+ def count(query)
86
+ log_debug "\t Count query: #{query.to_json}\n"
87
+ promises = @mongo_clients.map do |mongo_client_item|
88
+ mongo_client = mongo_client_item[1]
89
+ Concurrent::Promise.execute do
90
+ count_data_from_shard(mongo_client, query)
91
+ end
92
+ end
93
+ results = promises.map { |promise| promise.value[:count] }.sort.reverse
94
+ log_debug "Results sorted: #{results}\n"
95
+ merged_results = results.sum()
96
+ merged_results
97
+ end
98
+
99
+ def count_per_shard(query)
100
+ log_debug "\t Count query per shard: #{query.to_json}\n"
101
+ promises = @mongo_clients.map do |mongo_client_item|
102
+ mongo_client = mongo_client_item[1]
103
+ Concurrent::Promise.execute do
104
+ count_data_from_shard(mongo_client, query)
105
+ end
106
+ end
107
+
108
+ results = {
109
+ count: 0,
110
+ shards: {}
111
+ }
112
+
113
+ promises.map { |promise|
114
+ results[:shards][promise.value[:shard]] = promise.value[:count]
115
+ results[:count] = results[:count] + promise.value[:count]
116
+ }
117
+
118
+ log_debug "Results: #{results}\n"
119
+ results
120
+ end
121
+
122
+
123
+ def update_one()
124
+ # TODO: implement
125
+ end
126
+
127
+ def update_many()
128
+ # TODO: implement
129
+ end
130
+
131
+ def fetch_data_from_shard(mongo_client, query)
132
+ collection = mongo_client[@collection_name.to_sym]
133
+ results = collection.find(query).to_a
134
+ mongo_server = mongo_client&.cluster&.servers&.first
135
+ mongo_user = mongo_server&.options["user"] || ""
136
+ mongo_db = mongo_server&.options["database"] || ""
137
+ log_debug "\t\tfind() with mongo_client user: #{mongo_user}, database: #{mongo_db} returns #{results.count} items...\n"
138
+
139
+ {
140
+ shard: (mongo_user.nil? || mongo_user == "") ? mongo_db : mongo_user,
141
+ results: results
142
+ }
143
+ end
144
+
145
+ def count_data_from_shard(mongo_client, query)
146
+ collection = mongo_client[@collection_name.to_sym]
147
+ count = collection.count_documents(query)
148
+ count = 0 if count.nil?
149
+ mongo_server = mongo_client&.cluster&.servers&.first
150
+ mongo_user = mongo_server&.options["user"] || ""
151
+ mongo_db = mongo_server&.options["database"] || ""
152
+ log_debug "\t\tcount() with mongo_client user: #{mongo_user}, database: #{mongo_db} returns #{count}\n"
153
+
154
+ {
155
+ shard: (mongo_user.nil? || mongo_user == "") ? mongo_db : mongo_user,
156
+ count: count
157
+ }
158
+ end
159
+
160
+ def disconnect()
161
+ @mongo_clients.values.each do |client|
162
+ log_debug "\t Disconnecting from client #{client.to_s} ..."
163
+ client.close
164
+ log_debug " OK\n"
165
+ end
166
+ end
167
+
168
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_mongo_x
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Grzegorz Błaszczyk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-03-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: config
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: mongo
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.19.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.19.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.10.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.10.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 13.2.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 13.2.1
69
+ description: MongoDB client in Ruby that connects to dozens of Mongo databases, performs
70
+ queries simultaneously and gets the results in a unified way.
71
+ email: grzegorz.blaszczyk@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/helpers/loggable.rb
77
+ - lib/ruby_mongo_x.rb
78
+ homepage: https://rubygems.org/gems/ruby_mongo_x
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.4.6
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Multi-database Ruby MongoDB client
101
+ test_files: []