[SERVER-737] $allOrdered / $contains query operations for arrays Created: 11/Mar/10  Updated: 06/Dec/22  Resolved: 28/Jan/22

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

Type: New Feature Priority: Minor - P4
Reporter: Harry Marr Assignee: Backlog - Query Execution
Resolution: Won't Do Votes: 1
Labels: nc
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to SERVER-974 $subset query operator Closed
Assigned Teams:
Query Execution
Participants:

 Description   

It could be helpful to provide a new operator, similar to $all for arrays, that matches an ordered subset of items:

db.test.insert(

{'actions': [2, 6, 3, 8, 5, 3]}

);
db.test.insert(

{'actions': [6, 4, 2, 8, 4, 3]}

);
// This should find the first document, but not the second as only the first contains [6, 3, 8] in order
db.test.find({'actions': {'$contains': [6, 3, 8]}});

{ "_id" : ObjectId("4b993df679e2022d6d0086f3"), 'actions' : [2, 6, 3, 8, 5, 3] }

A couple of use cases:

  • Phrase matching in full-text search (storing stemmed terms as strings in an array)
  • Finding users on a website that have performed a certain sequence of actions

Also, allowing it to be optionally anchored to the start or end of an array would open up more possibilities:

  • Storing paths to files as individual segments of the path (by splitting the path by '/'), then finding files under a certain directory
    (or more generically, querying on items that have a list that is a path in a tree/hierarchy or a graph).


 Comments   
Comment by Asya Kamsky [ 09/Mar/18 ]

There's a blog post explaining how the above works and showing how to do non-strict ordered subset match also: http://www.kamsky.org/stupid-tricks-with-mongodb/how-to-match-a-strict-subset-of-an-array-in-order

Comment by Asya Kamsky [ 29/Jun/17 ]

For the record, this is how:

db.test.aggregate([
  {$match:{actions:{$all:[6,3,8]}}},
  {$addFields:{actions638:{$map:{
        input:{$range:[0,{$subtract:[{$size:"$actions"},2]}]},
        in:{$slice:["$actions","$$this",3]}
  }}}},
  {$match:{actions638:[6,3,8]}}
])

Comment by Asya Kamsky [ 29/Jun/17 ]

This is possible to do in aggregation framework using array expressions, but that's only helpful if this use case is for analytics.

Generated at Thu Feb 08 02:55:00 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.