0

Suppose in collection I have following documents:

[
  {"title": "t1", "fingerprint":[1, 2, 3]},
  {"title": "t2", "fingerprint":[4, 5, 6]}
]

I want to query documents in which at least one element in fingerprint at given position is equal to my querying array. For example: query([1, 7, 9]) should return [{"title": "t1", "fingerprint":[1, 2, 3]}]

query([1, 5, 9]) should return [{"title": "t1", "fingerprint":[1, 2, 3]}, {"title": "t2", "fingerprint":[4, 5, 6]}]

but query([5,1,9]) should return none records, because neither of records have same value at any of the positions in fingerprint array. How to write given query?

2
  • What is your mongo version ? Commented May 13, 2017 at 14:39
  • 3.4, but since it's playground project I can use whatever I need Commented May 13, 2017 at 14:48

3 Answers 3

3

When you are trying to match only documents with arrays where the sequence [ 1 2, 3 ] appears in values field and only in that exact order, you can do it this way:

db.testcol.find()
{ "_id" : "first", "value" : [ 1, 2, 3 ] }
{ "_id" : "second", "value" : [ 4, 5, 6 ] }
{ "_id" : "third", "value" : [ 1, 12, 13 ] }
{ "_id" : "fourth", "value" : [ 3, 2, 1 ] }
{ "_id" : "fifth", "value" : [ 1, 12, 13, 2, 3 ] }
{ "_id" : "sixth", "value" : [ 3, 2, 1, 2, 3 ] }
> db.testcol.aggregate([{$addFields:{ 
   cmp: {$in:[ 
      {$literal:[1,2,3]}, 
      {$map: {
         input:{$range:[0, {$subtract:[{$size:"$value"},2]}]}, 
         as:"l", 
         in: {$slice: [ "$value", "$$l", 3] } 
      }}
   ]}
}}])
{ "_id" : "first", "value" : [ 1, 2, 3 ], "cmp" : true }
{ "_id" : "second", "value" : [ 4, 5, 6 ], "cmp" : false }
{ "_id" : "third", "value" : [ 1, 12, 13 ], "cmp" : false }
{ "_id" : "fourth", "value" : [ 3, 2, 1 ], "cmp" : false }
{ "_id" : "fifth", "value" : [ 1, 12, 13, 2, 3 ], "cmp" : false }
{ "_id" : "sixth", "value" : [ 3, 2, 1, 2, 3 ], "cmp" : true }

What the $addFields stage does is checks if [1,2,3] appears in a list of three element arrays starting at position 0 of value array and moving forward till two positions before the end.

As you can see, it's now trivial to add a $match stage to filter out documents where cmp is not true.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use the .$index notation to perform such a search.

Example for your query([1, 7, 9])

db.coll.find({$or: [{"fingerprint.0": 1}, {"fingerprint.1": 7 }, {"fingerprint.2": 9}]})
{ "_id" : ObjectId("59170da907e34e73c0c93a9b"), "title" : "t1", "fingerprint" : [ 1, 2, 3 ] }

And query([1, 5, 9])

db.coll.find({$or: [{"fingerprint.0": 1}, {"fingerprint.1": 5 }, {"fingerprint.2": 9}]})
{ "_id" : ObjectId("59170da907e34e73c0c93a9b"), "title" : "t1", "fingerprint" : [ 1, 2, 3 ] }
{ "_id" : ObjectId("59170da907e34e73c0c93a9c"), "title" : "t2", "fingerprint" : [ 4, 5, 6 ] }

3 Comments

this only works for exactly 3 element arrays. In that case why not just use straight equality to compare?
Thx for your feedback @Asya, exact, it will only work for N elements arrays. In this case straight equality is not enough because Hubert wanted to get the records matching at least one of the conditions [1, 5, 9] should match both [1, 2, 3] and [4, 5, 9]
Hmm. The ok yeah - original question that led me here was a little different (it was based on matching all the elements in array being queried against.
0

$in operator is used to match a value against list of values.

According to above mentioned description please try executing following query in MongoDB shell

db.collection.find({fingerprint:{$in:[1,7,9]}})

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.