Question

Not sure if this is possible, but here goes.

I have a MongoDB (using morphia to access it) with a table like the following (simplified for this example, but the concept is the same):

{name:"Product A", parts:[{sku:"W-01"},{sku:"Y-01", qty:2}]}
{name:"Product B", parts:[{sku:"X-02"},{sku:"W-02"}]}
{name:"Product C", parts:[{sku:"Z-01"}]}

Now I want to find products with parts of which sku starts with "Y" or "Z". For the above docs, the first and third should be returned.

One possible query I can imagine is like this:

{$or:[{"parts":{"$elemMatch":{sku:/Y.*/}}},{"parts":{"$elemMatch":{sku:/Z.*/}}}]}

This needs to loop through the query arrays ["Y","Z"]

Is there any other way to do this? :)

Was it helpful?

Solution

Instead of doing a regular expression match, you could split out the first letter its own subkey as well:

{
    name:"Product A", 
    parts: [
        { s: "W", ku: "W-01" },
        { s: "Y", ku: "Y-01", qty:2 }
    ]
}

Otherwise you can simply do this regular expression match — you don't need the $elemMatch here either.

db.products.find( { "parts.sku: /^[YZ]/ } );

But it is better to use an $or for each of them, as then at least a little bit of the index can be used as the regular expression search is now a fixed-prefixed regular expression that internally gets rewritten to a range query (Y <= x < Z) or (Z <= x < [):

db.so.ensureIndex( { 'parts.sku': 1 } );
db.products.find( { $or: [
    { "parts.sku": /^Y/ },
    { "parts.sku": /^Z/ } 
] } );
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top