0

I hate to risk asking a duplicate question, but perhaps this is different from Passing Variables to a MongoDB View which didn't have any clear solution.

Below is a query to find the country for IP Address 16778237. (Outside the scope of this query, there is a formula that turns an IPV4 address into a number.)

I was wondering if we could abstract away this query out of NodeJS code, and make a view, so the view could be called from NodeJS. But the fields ipFrom and ipTo are indexed to get the query to run fast against millions of documents in the collection, so we can't return all the rows to NodeJS and filter there.

In MSSQL maybe this would have to be a stored procedure, instead of a view. Just trying to learn what is possible in MongoDB. I know there are functions, which are written in JavaScript. Is that where I need to look?

db['ip2Locations'].aggregate(
    {
        $match: 
        {
            $and: [
                {
                    "ipFrom": {
                        $lte: 16778237
                    }
                },
                {
                    "ipTo": {
                        $gte: 16778237
                    }
                },
                {
                    "active": true
                }
            ],
                    $comment: "where 16778237 between startIPRange and stopIPRange and the row is 'Active',sort by createdDateTime, limit to the top 1 row, and return the country"
        }
    },
    {
        $sort: 
        {
            'createdDateTime': - 1
        }
    },
    {
        $project: 
        {
            'countryCode': 1
        }
    },
    {
        $limit: 1
    }
)

Part 2 - after more research and experimenting, I found this is possible and runs with success, but then see trying to make a view below this query.

var ipaddr = 16778237
db['ip2Locations'].aggregate(
    {
        $match: 
        {
            $and: [
                {
                    "ipFrom": {
                        $lte: ipaddr
                    }
                },
                {
                    "ipTo": {
                        $gte: ipaddr
                    }
                },
                {
                    "active": true
                }
            ],
                    $comment: "where 16778237 between startIPRange and stopIPRange and the row is 'Active',sort by createdDateTime, limit to the top 1 row, and return the country"
        }
    },
    {
        $sort: 
        {
            'createdDateTime': - 1
        }
    },
    {
        $project: 
        {
            'countryCode': 1
        }
    },
    {
        $limit: 1
    }
)

If I try to create a view with a "var" in it, like this;

db.createView("ip2Locations_vw-lookupcountryfromip","ip2Locations",[ var ipaddr = 16778237 db['ip2Locations'].aggregate(

I get error:

[Error] SyntaxError: expected expression, got keyword 'var'

In the link I provided above, I think the guy was trying to figure how the $$user-variables work (no example here: https://docs.mongodb.com/manual/reference/aggregation-variables/). That page refers to $let, but never shows how the two work together. I found one example here: https://www.tutorialspoint.com/mongodb-query-to-set-user-defined-variable-into-query on variables, but not $$variables. I'm

db.createView("ip2Locations_vw-lookupcountryfromip","ip2Locations",[ db['ip2Locations'].aggregate( ...etc... "ipFrom": { $lte: $$ipaddr }

I tried ipaddr, $ipaddr, and $$ipaddr, and they all give a variation of this error:

[Error] ReferenceError: $ipaddr is not defined

In a perfect world, one would be able to do something like:

   get['ip2Locations_vw-lookupcountryfromip'].find({$let: {'ipaddr': 16778237})

or similar.

I'm getting that it's possible with Javascript stored in MongoDB (How to use variables in MongoDB query?), but I'll have to re-read that; seems like some blogs were warning against it.

I have yet to find a working example using $$user-variables, still looking.

NealWalters
  • 17,197
  • 42
  • 141
  • 251
  • @Minsky - don't exactly understand what you are asking. 16778237 needs to be the variable, so program can pass computed IP Address from web site visitor, and find out what country they are in. Code works now, but the big query has to be in the source code, and I was trying to research if there was a way to pull it out of the program, and save in MongoDB by any means. – NealWalters Nov 19 '20 at 02:53
  • I have added Part2 to my question, elaborating quite a bit and other things I have since tried. Thanks – NealWalters Nov 19 '20 at 03:37

1 Answers1

0

Interpretation

You want to query a view from some server side code, passing a variable to it.


Context

Can we use an external variable to recompute a View? Take the following pipeline:

var pipeline = [{ $group:{ _id:null, useless:{ $push:"$$NOW" } } }] 

We can pass system variables using $$. We can define user variables too, but the user defined variables are made out of:

  • Collection Data
  • System Variables.

Also, respect to your Part2:

A variable var variable="what" will be computed only once. Redefine variable="whatever" makes no difference in the view, it uses "what".

Conclusion

Views can only be re-computed with system variables, or user variables dependant on those system variables or collection data.

Added an answer to the post you link too.

Minsky
  • 2,277
  • 10
  • 19
  • But overall question was how is it possible (or is not possible) to store the query code in MongoDB, and not in program code. I know we can create a data access layer in our program, but I was trying to prevent multiple people from copying in long queries directly into their NodeJS programs. Are you saying functions should or should not be used? Not sure what you mean by "re-computed", I will read up on that. – NealWalters Nov 19 '20 at 21:03
  • 1
    @NealWalters I'm just telling what things won't work. It's rather difficult to know all pathways when there are so many. So, you can not pass a variable in any standard way. And I presume functions fall in that category: the function is computed only once, when the view is created. Any other attempt won't produce any effect. – Minsky Nov 20 '20 at 05:54