One of my biggest beefs with CFML in general is it...
# lucee
t
One of my biggest beefs with CFML in general is it's odd auto type-casting that no amount of
javacast
can fix. Examples: a string value
true
is automatically type cast as boolean, a string value
12-1
is suddenly a date, so is
35258-7
oddly. Most times it's not noticeable until you start interacting with MongoDB.
@Yogesh Lucid would you agree?
a
I'd like to see a repro of these. In my experience the issue is the other way around... where something is expecting a (eg) boolean, CFML will be very "forgiving" as to what it will take as a boolean: a truthy string, a numeric, a date, etc. Similar with numerics and dates and a few other things. But something that is a string (your example) seems to stay as a string until one uses it where some other type is expected..? What are you looking at?
y
I have seen these sorts of issues from time to time.
d
I wonder if the problem is MongoDB driver, because I've found that Lucee tracks datatypes very accurately, especially when javaCast() is used on a variable.
t
Copy code
arrayAppend(loc.criteria['$or'],{"#loc.sField#": { '$regex': trim(sData), '$options':'mi'} }, true);
where sData = "true" JavaCast helps nothing in this case. Good point that it could very well be the driver though.
a
OK I've made a portable repro case for this (@Travis: hint): https://trycf.com/gist/20bc094e1f926c25b03cb2997a7ae563/lucee5?theme=monokai
Copy code
loc.criteria['$or'] = [];
loc.sField = "someProperty";
sData = "true";
bData = true;

arrayAppend(
    loc.criteria['$or'],
    {
        "#loc.sField#": {
            '$regex': trim(sData), // "true"
            '$options':'mi',
            "bData": bData // true
        }
    },
    true
);

writeOutput(serializeJson(loc.criteria['$or']));
And this works exactly as I'd expect on CF2018+ and Lucee 5+:
Copy code
[{"someProperty":{"$options":"mi","bData":true,"$regex":"true"}}]
"true"
is still
"true"
and
true
is still
true
. What are you seeing? Or how do your expectations diverge from what it does?
t
Then this value is sent through the MongoDB driver, it responds with an error saying the $regex value must be a string. Conversion is happening somewhere along the line.
a
yup but this is a Mongo problem, not a Lucee problem. Or it's an intermediary problem somewhere that you're not telling us about. But Lucee is doing the correct thing here.
d
@Travis,
Copy code
arrayAppend(loc.criteria['$or'],{"#loc.sField#": { '$regex': trim(sData), '$options':'mi'} }, true);
The use of
trim()
is going to make
sData
a string.
Try changing that code to:
Copy code
arrayAppend(loc.criteria['$or'],{"#loc.sField#": { '$regex': javaCast("boolean", trim(sData)), '$options':'mi'} }, true);
(If you don't actually need the
trim()
just remove it)
t
The issue is reversed, MongoDB is getting that value as a boolean and not a string.
d
Sounds like this is a MongoDB or driver issue. Sounds like it's doing the conversion.
t
Quite possible.
d
Not being familiar with MongoDB, why are you setting $regex to true? Are you trying to filter for values that equal true?
Wouldn't there be a better way (other than a regex) to search for exact values?
t
I'm trying to filter for strings that contain "true"
d
Also, you could try changing your expression to something like
"^true$"
so it matches the exact value or
\btrue\b
if you're trying to match the word "true". Changing the expression above should prevent the value from being converted to a boolean.
✅ 1
I would think using a
$text
search would be more efficient (or some other command other than a regex for this use case)
t
That's my temporary workaround, but I would like it to also find results like "miscontrued"
Either way, the value received or interpreted by the driver is still a boolean and not a string.
Thanks for the $text tip, by the way.