Open proxygear opened 4 years ago
From what I see, I should start to dug from ActionService. However the actual implementation is in the engine ending in the ContentEntry. So my issue is Engine related and not Steam.
Refreshing my memory, the id method in mongoDB is _id
.
So I'm trying something like :
allEntries(
'books',
{ 'author_ids': findEntry('authors', 'an-author-slug') }
)
Still without success.
End of this, I'll update the doc :D
You should actually do something like this in the JS Action :
allEntries(
'books',
{
'author_ids': {
'$in': [findEntry('authors', 'an-author-slug')._id]
}
)
However, _id
return a string. To be working with Mongoid you should make it a BsonId Object.
Here is what the ruby counter part should be doing :
ContentEntry.where(
book_ids: {
'$in' => BSON::ObjectId.from_string(string_id)
}
).first
If the conversion to BSON::Object is omitted, it will not work.
My first guess would be update steam/lib/locomotive/adapters/mongodb.rb
to do some automatic conversion but ... meh ?
So my idea to fix it is to, within the JS Action to write something like this
var pseudo_id = "BSON(" + findEntry('authors', 'an-author-slug')._id + ")";
allEntries(
'books',
{
'author_ids': {
'$in': [pseudo_id]
}
)
And with a sanitizer, to handle the pseudo ids :
module Locomotive::Steam
module Adapters
module Mongodb
module IdsSanitizer
PSEUDO_ID_REGEXP = /^BSON\((?<id>[a-z0-9]+)\)$/.freeze
def self.call(data)
replace_leaf_strings_within(data, &method(:fix_pseudo_id))
end
def self.fix_pseudo_id(string)
result = PSEUDO_ID_REGEXP.match(string)
result ? BSON::ObjectId.from_string(result[:id]) : string
end
def self.replace_leaf_strings_within(data, &block)
case data.class
when Hash
{}.tap do |h|
data.each do |key, value|
h[key] = replace_leaf_strings_within(value, &block)
end
end
when Array
data.map { |value| replace_leaf_strings_within(value, &block) }
when String
block.call(data)
else
data
end
end
end
end
end
end
It could be used in steam/services/action_service.rb
line 99 :
def all_entries_lambda(liquid_context)
-> (type, conditions) { content_entry_service.all(type, sanitize_conditions(conditions), true) }
end
def sanitize_conditions(conditions)
Adapters::Mongodb::IdsSanitizer.call(conditions)
end
What do you think @did ?
PS: Using this monkey patch, I was able to solve my problem. I would like to do a pull request, however my solution is quite specific, I would like to discuss with some maintainer to see if something more generic cannot be done. Also, this solution is quite MongoDB specific, it will not work with wagon. But I guess that's another topic.
Let's say we have to collections
authors
andbooks
. A book has many authors and an author has many books. Great.In an action I tried something like this :
But it does not works. And I started to wonder how to do the following requests :
'authors.in' : ['a-first-author-slug', 'a-second-author-slug']
or'authors.ne' : 'a-first-author-slug'
Is it even possible ? From what I checked, I can access to
author_ids
:However it returns an array of
mongoDB
ids. In the other hand I can't access to the mongoDB id of an object :Some help with this confusion ?