MongoDB query with OR and Option

19 views
Skip to first unread message

Damian Helme

unread,
Oct 19, 2017, 9:59:42 AM10/19/17
to Lift
I've just come across a MongoDB query that isn't working as I expect. Are my expectations wrong or is it a bug?

When constructing the MongoDB query object, I'm using Options to conditionally add in search terms. 

It works as I expect for AND's but not for OR's ...

class Person extends MongoRecord[Person] with ObjectIdPk[Person] {
 
def meta = Person
 
object name extends StringField(this, 20)
  object age extends IntField(this)
}

object Person extends Person with MongoMetaRecord[Person] {
 
override def collectionName = "person"
}

val age : Option[Int] = None

// returns only records where name == "Joe"
val qry =("name" -> "Joe") ~ ("age" -> age)
Person.findAll(qry)

// returns all records
val qry1 =("$or" -> List[JObject](("name" -> "Joe"), ("age" -> age)))
Person.findAll(qry1)

When age is an None, I'm was hoping / expecting the search would only return records where name == Joe. Instead, it returns all rows. 

From a prettyRender, It seems that qry1 gets constructed as 

{

 "$or":[

   {

     "name":"Joe"

   },

   {

   }

 ]

}


The empty {} in the OR clause is what's causing all rows to be returned.

For comparison, in the AND case, the qry gets constructed as:

{

 "name":"Joe"

}



Is this a bug?


Matt Farmer

unread,
Oct 19, 2017, 10:07:10 AM10/19/17
to Lift
Interesting. The age part of the query collapses to a JNothing which we render as an empty object. In every other JSON context that is desirable, but not in Mongoland.

I’m not sure if this is an outright bug but it is certainly an unexpected interaction. The trouble is I’m not sure how we’d work around it on the framework level. From the application you can just not include the age part of the query, but I don’t know if we can filter empty objects out of ors without breaking code that may depend on this quirk.
--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

---
You received this message because you are subscribed to the Google Groups "Lift" group.
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tim Nelson

unread,
Oct 19, 2017, 10:53:10 AM10/19/17
to Lift
As Matt alluded to, this is related to how lift-json handles JNothing in JObjects.

lift-json will strip out *fields* of JObject that are JNothing, but it does not strip out empty JObjects from Lists.

Coming at this from the perspective of building mongo queries, I can see why you would expect that, though.

You'll need to filter out the part of the List you don't want in the $or statement.

Tim
Message has been deleted

Damian Helme

unread,
Oct 19, 2017, 11:20:19 AM10/19/17
to Lift
Thanks Tim, I see my oversight. 

 An $or List is a List of JObjects, not JFields, so removing a age->JNothing field from the JObject in the $or list still leaves you with an empty JObject.
Reply all
Reply to author
Forward
0 new messages