[SERVER-7770] $or should accept a proper object besides "x.y" for embedded-document filtering Created: 27/Nov/12  Updated: 06/Dec/22  Resolved: 24/Jul/19

Status: Closed
Project: Core Server
Component/s: JavaScript, Querying
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Minor - P4
Reporter: Cristián Assignee: Backlog - Query Team (Inactive)
Resolution: Won't Do Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Assigned Teams:
Query
Participants:

 Description   

$or accepts as filter an array of objects in the "document.attribute" style, which makes it impossible to build a dynamical query.

It should be a proper object in the form of "document:

{attribute1: 'value1', attribute2: 'value'}

". It seems cleaner, in line with js native form, and also allows to programmatically create a dynamic query (specially if you don't have a fixed set of attributes to search, which seems logical in a schema-less model).



 Comments   
Comment by Asya Kamsky [ 24/Jul/19 ]

We would not be able to change the syntax of query language without breaking existing applications which rely on current semantics. Closing as won't do.

Comment by Stennie Steneker (Inactive) [ 19/Dec/12 ]

Hi Cristián,

My earlier JavaScript example was pushing a custom userInput value into the $or clause. You could build this programatically and would not have to hardcode the key or value.

 "custom": {"foo": "bar", "bar": "baz"}

The syntax you've suggested is already used by dot notation to exactly match a subdocument. If your subdocument contained {{

{"foo": "bar", "bar": "baz"}

}} (and in that specific order) you will get a result.

So a few further examples:

1) Exact match subdocument against userInput criteria and a subdocument called custom:

   var userInput = {foo: "bar", bar: "baz"};
   db.customer.find({custom: userInput});

2) Build $or clauses with user-provided criteria:

	var userInput = { "foo" : "bar", "bar" : "baz" };
	var subDoc = 'custom';
	var query = {};
	query["$or"]=[];
	for (var key in userInput) {
		var customKey = {};
		customKey[subDoc + '.' + key] = userInput[key];
		query["$or"].push(customKey);
	}
	db.customer.find(query);

As per the second example, you should be able to build up your query (including subdocument and key names) programatically.

Cheers,
Stephen

Comment by Cristián [ 05/Dec/12 ]

Hi Stephen,

I see your point, but try going back one step and you'll see what I mean: "custom.bar" could be anything, I don't know in advance it could be custom.xxx or custom.yyy.

  1. pseudo.code start

#
my db looks like this:

customer = {
name: "foo bar",
custom:

{ foo: "bar", bar: "baz" }

};
#

userinput =

{foo: "bar", bar: "baz"}
  1. I SHOULD be able to do this:

query["$or"].push(

{custom: userinput}

)

  1. but I can't, i'm forced to use a literal "custom.foo": "bar"

The db should accept as input:

1. "custom.foo": "bar", "custom.bar": "baz"

and

2. "custom":

{"foo": "bar", "bar": "baz"}

js-wise the second should be the 'proper' way of formatting the object, so the db should be able to read this. but why is it important in my case? because '

{"foo": "bar", "bar": "baz"}

' could start as an empty object '{}' and then I can programmatically build it (example: emptyObject[someVar] = someValue) but that's not possible if I'm forced to use "custom.foo": "bar", specially if I don't know what "foo" is in advance (it can be "bar", "baz", "etc".. any value).

Cheers, c.

  1. pseudo.code end
Comment by Stennie Steneker (Inactive) [ 05/Dec/12 ]

Hi Cristián,

I'm not sure what driver you are using, but if you are building your queries dynamically in your application, you shouldn't have to hard code the "custom.bar" string. You can use a variable to populate your query (and should be properly sanity checking/untainting any user-provided input).

For example, in the mongo shell:

	var userInput = { 'custom.bar' : 'baz' };
	var query = {};
	query["$or"]=[];
	query["$or"].push({"custom.foo":"xyz"});
	query["$or"].push(userInput);
	
	db.customer.find(query)

Cheers,
Stephen

Comment by Cristián [ 27/Nov/12 ]

Sure, here's an example.

Let's say I have the following schema in my head: db.customer, where db.customer has an attribute called custom. A representation of a single record could look like this:

customer = {
name: "foo bar",
custom:

{ foo: "bar", bar: "baz" }

};

If want to do an $or query searching for, let's say, custom.bar = "baz", then I can use something like:

db.customer.find( { name: "foo bar", $or: [

{ "custom.foo": "xyz" }

,

{"custom.bar": "baz" }

] } )

This force me to actually write in my code the string "custom.bar", which is not always possible.

Real case? Here's one:

I'm writing an app where I let the users dynamically add attributes to the "custom" attribute, so the schema could look like "db.customer.custom.ANYTHING = 'foo bar'".
Now I'm trying to run a query based on this dynamic attributes (attributes that I cannot hardwire to the code because they are, well, dynamic) so I need to dynamically write this query.

If I'm receiving this attributes and their values in a form of a variable (could come from a db, webform, etc) I can't dynamically write "custom.SOME_KEY = 'SOME_VALUE'", but I could start with an empty object and then add the proper keys an values like "theobject[SOME_KEY] = 'SOME_VALUE'".

At least from this case it makes complete sense to be able to pass "custom:

{foo: 'bar'}

" as an $or filter instead of "custom.foo = 'bar'".

Did my best trying to explain, hope it works.

Comment by Eliot Horowitz (Inactive) [ 27/Nov/12 ]

I'm not sure what you mean exactly.
What is the query you are trying to do? (english, or code, or something)

Generated at Thu Feb 08 03:15:33 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.