Defacto
Defacto

Reputation: 141

Find most similar array using MongoDB

I am trying to find the minimum distance between arrays of numbers using a MongoDB query. My tech stack is Node.js+Mongoose with MongoDB 4.

Here's our input array, A:

A = [1, 2, 3, 4, 5]

And stored within MongoDB, we have objects like this:

[
  {
    id: 0
    nums: [4, 5, 6, 7, 8]
  },
  {
    id: 1
    nums: [-500, 50.2, 60, 74, 1]
  },
  {
    id: 2
    nums: [9, 5, 32, -7, 5]
  }
]

What I'm trying to do is sort the objects using the euclidian distance formula. For example, if we wanted to compare array A with id:0 in Mongo, I want to apply the Euclidean distance formula:

distance = Math.sqrt((a1-b1)^2 + (a2-b2)^2 + ... + (an-bn)^2)

In our case:

x = Math.sqrt((1-4)^2 + (2-5)^2 + (3-6)^2 + (4-7)^2 + (5-8)^2)

I want to find x for every array in the database, then sort by the minimum x value. In other words, I want to find the array that is most similar to our input.

I have some written basic queries in MongoDB before, but I'm really not sure how to approach this type of problem. Any help would be greatly appreciated.

Upvotes: 2

Views: 346

Answers (1)

mickl
mickl

Reputation: 49945

You can start with $zip to "pair" your input array with nums. Then you can run $reduce to calculate Euclidean formula:

db.collection.aggregate([
    {
        $addFields: {
            distance: {
                $let: {
                    vars: {
                        pow: {
                            $reduce: {
                                input: { $zip: { inputs: [ [1, 2, 3, 4, 5], "$nums" ] } },
                                initialValue: 0,
                                in: {
                                    $add: [ 
                                        "$$value", 
                                        { $pow: [ 
                                            { $subtract: [ { $arrayElemAt: [ "$$this", 0 ] }, { $arrayElemAt: [ "$$this", 1 ] } ] } , 2 ] } 
                                        ]
                                }
                            }
                        }
                    },
                    in: { $sqrt: "$$pow" }
                }
            }
        }
    },
    {
        $sort: { distance: 1 }
    }
])

Mongo Playground

Upvotes: 2

Related Questions