Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MONGOID-5582 Correctly interpret shard keys in embedded documents #5576

Merged
merged 2 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions lib/mongoid/shardable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,22 @@ def shard_key_fields
self.class.shard_key_fields
end

# Returns the selector that would match the current version of this
# document.
# Returns the selector that would match the defined shard keys. If
# `prefer_persisted` is false (the default), it uses the current values
# of the specified shard keys, otherwise, it will try to use whatever value
# was most recently persisted.
#
# @param [ true | false ] prefer_persisted Whether to use the current
# value of the shard key fields, or to use their most recently persisted
# values.
#
# @return [ Hash ] The shard key selector.
#
# @api private
def shard_key_selector
selector = {}
shard_key_fields.each do |field|
selector[field.to_s] = send(field)
def shard_key_selector(prefer_persisted: false)
jamis marked this conversation as resolved.
Show resolved Hide resolved
jamis marked this conversation as resolved.
Show resolved Hide resolved
shard_key_fields.each_with_object({}) do |field, selector|
selector[field.to_s] = shard_key_field_value(field.to_s, prefer_persisted: prefer_persisted)
end
selector
end

# Returns the selector that would match the existing version of this
Expand All @@ -72,11 +76,31 @@ def shard_key_selector
#
# @api private
def shard_key_selector_in_db
selector = {}
shard_key_fields.each do |field|
selector[field.to_s] = new_record? ? send(field) : attribute_was(field)
shard_key_selector(prefer_persisted: true)
end

# Returns the value for the named shard key. If the field identifies
# an embedded document, the key will be parsed and recursively evaluated.
# If `prefer_persisted` is true, the value last persisted to the database
# will be returned, regardless of what the current value of the attribute
# may be.
#
# @param [String] field The name of the field to evaluate
# @param [ true|false ] prefer_persisted Whether or not to prefer the
# persisted value over the current value.
#
# @return [ Object ] The value of the named field.
jamis marked this conversation as resolved.
Show resolved Hide resolved
#
# @api private
def shard_key_field_value(field, prefer_persisted:)
if field.include?(".")
relation, remaining = field.split(".", 2)
send(relation)&.shard_key_field_value(remaining, prefer_persisted: prefer_persisted)
elsif prefer_persisted && !new_record?
attribute_was(field)
else
send(field)
end
selector
end

module ClassMethods
Expand Down
14 changes: 14 additions & 0 deletions spec/mongoid/shardable_models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,17 @@ class SmDriver
class SmNotSharded
include Mongoid::Document
end

class SmReviewAuthor
include Mongoid::Document
embedded_in :review, class_name: "SmReview", touch: false
field :name, type: String
end

class SmReview
include Mongoid::Document

embeds_one :author, class_name: "SmReviewAuthor"

shard_key "author.name" => 1
end
Loading