{"id":13092,"date":"2022-04-20T10:22:45","date_gmt":"2022-04-20T17:22:45","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=13092"},"modified":"2025-06-13T23:34:37","modified_gmt":"2025-06-14T06:34:37","slug":"creating-python-and-javascript-user-defined-functions-for-geospatial-queries","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/","title":{"rendered":"Creating Python and JavaScript User Defined Functions For Geospatial Queries"},"content":{"rendered":"<p><span style=\"font-weight: 400\">SQL++ queries can access data stored in your Couchbase cluster in a variety of ways. There are situations where having the business logic as part of your data queries can also be beneficial. SQL++ supports this with User Defined Functions (UDFs) that have been available since <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Couchbase 7.0<\/span><\/a><span style=\"font-weight: 400\">.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">In this blog post, we create a UDF in JavaScript that queries points from a user\u2019s location, dynamically, using SQL++. Additionally, we perform the same distance calculations with a UDF in Python within the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/analytics\/introduction.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Analytics service<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Our geospatial query use case<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Our application will generate geographic points of interest from our database that are near a user\u2019s GPS location, similar to services like Google Maps, shown in the screenshot below. For this example, we will use the <\/span><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/ref\/travel-app-data-model.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">travel-sample dataset<\/span><\/a><span style=\"font-weight: 400\"> that is available in a sample bucket provided by Couchbase.<\/span><\/p>\n<p><span style=\"font-weight: 400\">In particular, we are interested in seeing the <\/span><i><span style=\"font-weight: 400\">landmarks <\/span><\/i><span style=\"font-weight: 400\">and <\/span><i><span style=\"font-weight: 400\">airports <\/span><\/i><span style=\"font-weight: 400\">around the user\u2019s current location. This cannot be achieved using a SQL++ query directly as the distance calculation is based on the real-time geographic location of the user. SQL++ supports defining UDFs in JavaScript to perform custom logic in the queries.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-13094\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/04\/image_2022-04-20_102207935-504x1024.png\" alt=\"Map shwoing searhc for local points of interest\" width=\"504\" height=\"1024\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/image_2022-04-20_102207935-504x1024.png 504w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/image_2022-04-20_102207935-148x300.png 148w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/image_2022-04-20_102207935-300x610.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/image_2022-04-20_102207935-10x20.png 10w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/image_2022-04-20_102207935.png 519w\" sizes=\"auto, (max-width: 504px) 100vw, 504px\" \/><\/p>\n<h2><span style=\"font-weight: 400\">Calculating distances from GPS coordinates<\/span><\/h2>\n<p><span style=\"font-weight: 400\">There are many ways to calculate the distance between two sets of GPS coordinates. In this example, we will calculate the distance using the <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Haversine_formula\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Haversine Formula<\/span><\/a><span style=\"font-weight: 400\">. It gives the approximate distance between two GPS coordinates by considering the path to be a sphere rather than a straight line distance.<\/span><\/p>\n<p><span style=\"font-weight: 400\">JavaScript code to calculate geographic distances is shown in this sample:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:js decode:true\">function degreesToRadians(degrees) {\r\n\u00a0\u00a0\u00a0return degrees * Math.PI \/ 180;\r\n\u00a0}\r\n\r\n\u00a0function distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {\r\n\r\n\u00a0\u00a0\u00a0var earthRadiusKm = 6371;\r\n\u00a0\u00a0\u00a0var dLat = degreesToRadians(lat2-lat1);\r\n\u00a0\u00a0\u00a0var dLon = degreesToRadians(lon2-lon1);\r\n\r\n\u00a0\u00a0\u00a0lat1 = degreesToRadians(lat1);\r\n\u00a0\u00a0\u00a0lat2 = degreesToRadians(lat2);\r\n\r\n\u00a0\u00a0\u00a0var a = Math.sin(dLat\/2) * Math.sin(dLat\/2) +\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Math.sin(dLon\/2) * Math.sin(dLon\/2) * Math.cos(lat1) * Math.cos(lat2);\r\n\u00a0\u00a0\u00a0var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\r\n\u00a0\u00a0\u00a0return earthRadiusKm * c;\r\n}<\/pre>\n<p><span style=\"font-weight: 400\">We define two JavaScript functions\u2013one that performs the conversion between degrees and radians and another that calculates the distance in kilometers between the GPS coordinates from the other function.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Importing UDFs into Couchbase<\/span><\/h2>\n<p><span style=\"font-weight: 400\">These JavaScript functions can now be imported into Couchbase using the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/createfunction.html#create-function-external\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">REST API<\/span><\/a><span style=\"font-weight: 400\">, as shown below with the <\/span><i><span style=\"font-weight: 400\">curl <\/span><\/i><span style=\"font-weight: 400\">command:<\/span><\/p>\n<pre class=\"wrap:true trim-whitespace:false lang:sh decode:true\">curl -v -X POST https:\/\/localhost:8093\/evaluator\/v1\/libraries\/math -u &lt;user&gt;:&lt;password&gt; -d 'function degreesToRadians(degrees) {  \r\n  return degrees * Math.PI \/ 180;\r\n  }\r\n  function distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {\r\n  var earthRadiusKm = 6371;\r\n  var dLat = degreesToRadians(lat2-lat1);\r\n  var dLon = degreesToRadians(lon2-lon1);\r\n  lat1 = degreesToRadians(lat1);\r\n  lat2 = degreesToRadians(lat2);\r\n  var a = Math.sin(dLat\/2) * Math.sin(dLat\/2) +\r\n    Math.sin(dLon\/2) * Math.sin(dLon\/2) * Math.cos(lat1) * Math.cos(lat2); \r\n  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\r\n  return earthRadiusKm * c;\r\n}'<\/pre>\n<p><span style=\"font-weight: 400\">After this step, the UDF can be defined in the web console\u2019s <strong>Query Editor<\/strong>:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:tsql decode:true \">CREATE FUNCTION degreesToRadians(a) LANGUAGE JAVASCRIPT AS \"degreesToRadians\" AT \"math\"\r\n\r\nCREATE FUNCTION distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) LANGUAGE JAVASCRIPT AS \"distanceInKmBetweenEarthCoordinates\" AT \"math\"<\/pre>\n<p><span style=\"font-weight: 400\">Here, the <\/span><i><span style=\"font-weight: 400\">math<\/span><\/i><span style=\"font-weight: 400\"> reference is to the JavaScript <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-rest-api\/functions.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">library<\/span><\/a><span style=\"font-weight: 400\"> that we created to evaluate the UDF.<\/span><\/p>\n<p><span style=\"font-weight: 400\">The UDF can now be tested with sample GPS coordinates in SQL++ using the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/execfunction.html\" target=\"_blank\" rel=\"noopener\"><i><span style=\"font-weight: 400\">Execute <\/span><\/i><span style=\"font-weight: 400\">Function<\/span><\/a><span style=\"font-weight: 400\"> as shown below<\/span><\/p>\n<pre class=\"decode-attributes:false lang:default decode:true \">EXECUTE FUNCTION distanceInKmBetweenEarthCoordinates(51.5, 0, 38.8, -77.1)<\/pre>\n<p><span style=\"font-weight: 400\">We can observe that the function works as intended when we provide the GPS coordinates manually to the function.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Connecting the UDF to Couchbase data<\/span><\/h2>\n<p><span style=\"font-weight: 400\">In the <em>travel-sample<\/em> dataset, we have GPS coordinates of the <\/span><i><span style=\"font-weight: 400\">landmarks <\/span><\/i><span style=\"font-weight: 400\">and <\/span><i><span style=\"font-weight: 400\">airports <\/span><\/i><span style=\"font-weight: 400\">along with other places of interest like <\/span><i><span style=\"font-weight: 400\">hotels<\/span><\/i><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><span style=\"font-weight: 400\">We can integrate them into our queries like the one below:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:tsql decode:true\">SELECT distanceInKmBetweenEarthCoordinates(a.geo.lat, a.geo.lon, 51.509865, -0.118092) AS distance,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.airportname,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.city\r\nFROM `travel-sample`.inventory.airport a\r\nORDER BY distance ASC\r\nLIMIT 10;<\/pre>\n<p><span style=\"font-weight: 400\">This query returns a list of the ten closest airports to the user\u2019s location (<\/span><i><span style=\"font-weight: 400\">51.509865, -0.118092<\/span><\/i><span style=\"font-weight: 400\">). We provide the latitude (<\/span><i><span style=\"font-weight: 400\">a.geo.lat<\/span><\/i><span style=\"font-weight: 400\">) and longitude (<\/span><i><span style=\"font-weight: 400\">a.geo.lon<\/span><\/i><span style=\"font-weight: 400\">)<\/span> <span style=\"font-weight: 400\">fields that are embedded in the documents using the power of SQL++.<\/span><\/p>\n<pre class=\"decode-attributes:false lang:js decode:true\">[\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"All Airports\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 0.6998675034052988\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"Waterloo International\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 0.7880158040048914\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"London St Pancras\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 2.289359875405007\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"Euston Station\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 2.30782110865356\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"St Pancras Railway Station\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 2.582290289682563\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"Paddington Station\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 4.069442660124984\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"London Heliport\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 6.062824964656381\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"Elstree\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"Elstree\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 8.735152174563803\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"City\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 12.009592036043564\r\n\u00a0\u00a0\u00a0},\r\n\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"airportname\": \"London - Kings Cross\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\"distance\": 16.891716659500467\r\n\u00a0\u00a0\u00a0}\r\n\u00a0]<\/pre>\n<p><span style=\"font-weight: 400\">Similarly, we can calculate the points of interest around the user using the <\/span><i><span style=\"font-weight: 400\">landmark <\/span><\/i><span style=\"font-weight: 400\">collection in increasing distance from the user:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:tsql decode:true\">SELECT distanceInKmBetweenEarthCoordinates(l.geo.lat, l.geo.lon, 51.509865, -0.118092) AS distance,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0l.activity,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0l.city,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0l.content\r\nFROM `travel-sample`.inventory.landmark l\r\nORDER BY distance ASC\r\nLIMIT 10;<\/pre>\n<p><span style=\"font-weight: 400\">Results of the query showing nearby landmarks:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:js decode:true\">[\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Somerset House is home to three art galleries:\u00a0 The exceptional '''Courtauld Institute''' displays a collection of 19th and 20th century art, including well-known works by Degas, Matisse and Kandinsky; The Gilbert Collection presents a collection of decorative art; and The Hermitage Rooms, the most recent addition to Somerset House, hosts temporary exhibitions of works on loan from the Hermitage Museum in Saint Petersburg. The central courtyard is filled with fountains in the Summer, but in the Winter, an ice rink is installed, it is very popular, so visitors should book in advance, or expect to wait a long time to skate.\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.10940067520415872\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Cleopatra's Needle originated in the ancient [[Egypt]]ian city of [[Cairo\/Heliopolis|Heliopolis]], in the Temple of Atum, but the Romans moved it to [[Alexandria]] in 12 BC.\u00a0 In 1819, viceroy Mehemet Ali presented Cleopatra's Needle to the British, commemorating military victories in Egypt, but it remained in Alexandria until 1877 when transportation was arranged to bring it to London.\u00a0 On the voyage, the ship capsized in a storm, killing six crewmembers.\u00a0 Cleopatra's Needle was thought to be lost, but Spanish trawlers found it afloat a few days later, and after some repairs, it arrived in London on 21 Jan 1878. The obelisk is flanked by two faux-sphinxes, which show the effects of bombings of London during World War II.\u00a0 Today, Cleopatra's Needle shows some wear from exposure to London's damp weather.\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.2153782246329736\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"buy\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Daily second-hand book sale near the bank of the Thames. A nice place to just browse for books (classic and modern), maps and prints.\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.329776385402355\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"[[London]] (in [[London\/Covent Garden|Covent Garden]])\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.34889537479151833\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"London's most famous and popular skateboarding area, situated partly underneath Queen Elizabeth Hall along Queen's Walk and the Thames.\u00a0 Also popular with graffiti artists, BMXers and so forth.\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.36487940944981834\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Tucked under Waterloo Bridge, BFI Southbank, formerly known as the National Film Theatre, pitches itself as the home of film and has three screens showing classic (including silent), foreign language and less mainstream films. Recently redeveloped, it now has a new entrance on Theatre Alley, a shop dedicated to film, an interactive exhibition space and an excellent bar\/restaurant at the back. Visitors can also access the Mediatheque - wind your way through the BFI's extensive film and TV archive for free.\u00a0 Cool bar and restaurant. Tickets are generally available on the spur of the moment.\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.378692262237853\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Music venue hosting daily performances. | image=Queen Elizabeth Hall.jpg\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.3859430181613397\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"drink\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"The antidote to gay bars: a pub-like atmosphere and great music. | image=The Retro Bar.jpg\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.39732030942983415\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"see\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Three large auditoriums, the Olivier, the Lyttelton and the Cottesloe. The Olivier theatre is the largest with an open stage and a fan shaped auditorium around it. This ensures that all seats provide a good view. Most of the more 'popular' productions are put on here as the space provided is much larger than most theatres. The Lyttelton theatre is more traditional with a procenium arc with good views from most seats. The Cottesloe is a small studio theatre, seating around 400. Some tickets will be available on the day, either day seats (arrive before 09:30 and queue) or standby (arrive before 6PM and queue), or you can buy online. Popular shows, especially those around Christmas in the Olivier sell out months in advance. Tickets to The National Theatre are generally better value than most other theatres. There is also the '\u00a310 Travelex' season in the summer that provides a large number (over 100,000 seats a year) at \u00a310. Booking in advance is required for these. There is also an exhibition space in the Lyttelton theatre foyer that frequently holds popular photographic exhibitions. Free jazz is often played in the evening in the ground floor foyer. During summer there is a free daily outdoor festival of performance, music, comedy and cabaret known as Watch This Space. Deckchairs (and artificial grass) are provided to watch on. Free exhibitions. Backstage tours \u00a35. (https:\/\/www.nationaltheatrelondon.com\/tickets\/)\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.42625112040817054\r\n\u00a0},\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"activity\": \"drink\",\r\n\u00a0\u00a0\u00a0\"city\": \"London\",\r\n\u00a0\u00a0\u00a0\"content\": \"Free nightly music events.\u00a0 The best place to sample underground electro, indie, dub-step and more.\",\r\n\u00a0\u00a0\u00a0\"distance\": 0.4323026974543284\r\n\u00a0}\r\n]<\/pre>\n<p><span style=\"font-weight: 400\">If we run these queries for multiple users at the same time, we might run into performance issues as we are using the compute resources that are part of the Couchbase cluster.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">In such scenarios, Couchbase Analytics could reduce the impact on your cluster. <\/span><span style=\"font-weight: 400\">Couchbase Analytics is designed to efficiently run complex queries over many records. Complex queries can include large ad hoc join, set, aggregation, and grouping operations\u2013any of which may result in long-running queries, high CPU usage, high memory consumption, or excessive network latency due to data fetching and cross node coordination.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">User Defined Functions with Couchbase Analytics<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Couchbase Analytics allows us to define and use <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/analytics\/appendix_5_python.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">User Defined Functions in Python<\/span><\/a><span style=\"font-weight: 400\"> but at the time of writing requires you to <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/developer-preview\/preview-mode.html#how-do-i-enable-the-developer-preview-mode\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">enable Developer Preview<\/span><\/a><span style=\"font-weight: 400\"> mode in Couchbase Server. This can be done with the following command:<\/span><\/p>\n<pre class=\"decode-attributes:false lang:sh decode:true\">$ \/opt\/couchbase\/bin\/couchbase-cli enable-developer-preview \\\r\n  --enable -c localhost:8091 -u &lt;username&gt; -p &lt;password&gt;<\/pre>\n<p><span style=\"font-weight: 400\">The next step is to create a Python package, locally, on the development environment with the Python UDF. In this case, the UDF is a method to calculate the distance between two GPS coordinates.<\/span><\/p>\n<pre class=\"decode-attributes:false lang:python decode:true\"># distance.py\r\nfrom geopy import distance\r\n\r\nclass distance_calculation:\r\n\u00a0\u00a0\u00a0def calculate_distance(self, lat1, lon1, lat2, lon2) -&gt; float:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"\"\"Calculate Distance using geodesic distance\"\"\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return distance.distance((lat1, lon1), (lat2, lon2)).km<\/pre>\n<p><span style=\"font-weight: 400\">Here, we calculate the <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Geodesics_on_an_ellipsoid\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">geodesic distance<\/span><\/a><span style=\"font-weight: 400\"> (the shortest distance between points along a curved path) between the two GPS coordinates with the help of a library, <\/span><a href=\"https:\/\/geopy.readthedocs.io\/\" target=\"_blank\" rel=\"noopener\"><i><span style=\"font-weight: 400\">geopy<\/span><\/i><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Packaging the UDF<\/span><\/h3>\n<p><span style=\"font-weight: 400\">To package the library, we use a package <\/span><a href=\"https:\/\/shiv.readthedocs.io\/en\/latest\/\" target=\"_blank\" rel=\"noopener\"><i><span style=\"font-weight: 400\">shiv<\/span><\/i><\/a> <span style=\"font-weight: 400\">that can package the code along with its requirements for any platform. Here, we are using Linux as Couchbase Server is running on a Linux environment within Docker.<\/span><\/p>\n<pre class=\"decode-attributes:false lang:sh decode:true \">shiv -o distance.pyz --site-packages . --platform manylinux2010_x86_64 --python-version 39 --only-binary=:all: geopy<\/pre>\n<p><span style=\"font-weight: 400\">In order to upload this binary package with the UDF to Couchbase, we need to use the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/analytics\/rest-library.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">REST API<\/span><\/a><span style=\"font-weight: 400\"> for the Analytics service.\u00a0<\/span><\/p>\n<pre class=\"decode-attributes:false lang:sh decode:true \">curl -X POST -u &lt;username&gt;:&lt;password&gt; -F \"type=python\" -F \"data=@.\/distance.pyz\" localhost:8095\/analytics\/library\/Default\/pylib<\/pre>\n<p><span style=\"font-weight: 400\">This uploads the packaged UDF into the <\/span><i><span style=\"font-weight: 400\">pylib<\/span><\/i><span style=\"font-weight: 400\"> library in the <\/span><i><span style=\"font-weight: 400\">default <\/span><\/i><span style=\"font-weight: 400\">scope (formerly <\/span><span style=\"font-weight: 400\">dataverse<\/span><span style=\"font-weight: 400\">) of the Analytics environment. We can now define the UDF in the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/analytics\/run-query.html#Using_analytics_workbench\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Analytics Workbench<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><span style=\"font-weight: 400\">This definition statement indicates that we are defining a UDF named <\/span><i><span style=\"font-weight: 400\">distance_in_km <\/span><\/i><span style=\"font-weight: 400\">that can be called from the Python function <\/span><i><span style=\"font-weight: 400\">calculate_distance <\/span><\/i><span style=\"font-weight: 400\">defined in class <\/span><i><span style=\"font-weight: 400\">distance_calculation<\/span><\/i><span style=\"font-weight: 400\"> within the Python module <\/span><i><span style=\"font-weight: 400\">distance.<\/span><\/i><\/p>\n<pre class=\"decode-attributes:false lang:tsql decode:true\">CREATE ANALYTICS FUNCTION distance_in_km(lat1, lon1, lat2, lon2) AS \"distance\",\r\n\u00a0\u00a0\"distance_calculation.calculate_distance\" AT pylib;<\/pre>\n<p><span style=\"font-weight: 400\">Now we can use the UDF in our Analytics queries the same way we used the UDF in our SQL++ queries.<\/span><\/p>\n<pre class=\"decode-attributes:false lang:tsql decode:true\">SELECT distance_in_km(51.5, 0, 38.8, -77.1) AS \"distance\"\r\n\r\nRESULTS:\r\n[\r\n\u00a0{\r\n\u00a0\u00a0\u00a0\"distance\": 5933.5299530300545\r\n\u00a0}\r\n]<\/pre>\n<h3><span style=\"font-weight: 400\">Mapping Data from Data Service in Analytics Service<\/span><\/h3>\n<p><span style=\"font-weight: 400\">In order to query the data in the Data Service from the Analytics Service, we need to <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/analytics\/manage-datasets.html#mapping-collections-from-the-data-service\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">map<\/span><\/a><span style=\"font-weight: 400\"> the <\/span><i><span style=\"font-weight: 400\">travel-sample<\/span><\/i><span style=\"font-weight: 400\"> data collections in Analytics that creates a real-time shadow copy of the data in the Data Service in Analytics. For this example, we need to map the collections with geographical data, namely the <\/span><i><span style=\"font-weight: 400\">landmark, airport <\/span><\/i><span style=\"font-weight: 400\">and<\/span><i><span style=\"font-weight: 400\"> hotel<\/span><\/i><span style=\"font-weight: 400\"> collections from the inventory scope in the<\/span><i><span style=\"font-weight: 400\"> travel-sample<\/span><\/i><span style=\"font-weight: 400\"> bucket.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Running the Analytics UDF against Couchbase Data<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Now, we can run the same queries that we were running before in SQL++ but with the Analytics Service. Only the UDF name has changed. The rest of the interface is similar to what we had with the SQL++ queries. The results will also be similar to the earlier results.<\/span><\/p>\n<pre class=\"decode-attributes:false lang:tsql decode:true\">SELECT distance_in_km(a.geo.lat, a.geo.lon, 51.509865, -0.118092) AS distance,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.airportname,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0a.city\r\nFROM `travel-sample`.inventory.airport a\r\nORDER BY distance ASC\r\nLIMIT 10;\r\n\r\nSELECT distance_in_km(l.geo.lat, l.geo.lon, 51.509865, -0.118092) AS distance,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0l.activity,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0l.city,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0l.content\r\nFROM `travel-sample`.inventory.landmark l\r\nORDER BY distance ASC\r\nLIMIT 10;<\/pre>\n<p><span style=\"font-weight: 400\">This approach is suitable when we want to run these queries without impacting the <\/span><i><span style=\"font-weight: 400\">Data Service<\/span><\/i><span style=\"font-weight: 400\"> which is commonly used for our transactional data. The data is synced between the <\/span><i><span style=\"font-weight: 400\">Data <\/span><\/i><span style=\"font-weight: 400\">and the<\/span><i><span style=\"font-weight: 400\"> Analytics Service <\/span><\/i><span style=\"font-weight: 400\">internally in real-time in Couchbase.<\/span><\/p>\n<h2><span style=\"font-weight: 400\">Summary<\/span><\/h2>\n<p><span style=\"font-weight: 400\">In this blog post, you\u2019ve learned to create a User Defined Function (UDF) in JavaScript that\u00a0 calculates distances between two GPS coordinates. You saw how to import the UDF into Couchbase and then integrate it into a SQL++ query to power applications that could provide points of interest around a user. We also showcased how you can perform the same distance calculation in a Python-based UDF using the Analytics service to reduce impact on your transactional Couchbase cluster.<\/span><\/p>\n<p><span style=\"font-weight: 400\">For further reading and reference, see the following resources:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none\">\n<ul>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.couchbase.com\/blog\/n1ql-user-defined-functions\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">SQL++ Nows Supports User Defined Functions<\/span><\/a><span style=\"font-weight: 400\">\u00a0(Blog)<\/span><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/ref\/travel-app-data-model.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Couchbase Travel Sample App<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/createfunction.html#create-function-external\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400\">Couchbase REST API for creating functions<\/span><\/a><span style=\"font-weight: 400\"> (Docs)<\/span><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/analytics\/appendix_5_python.html\" target=\"_blank\" rel=\"noopener\">Creating Python UDFs in Couchbase Analytics Service<\/a> (Docs)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>SQL++ queries can access data stored in your Couchbase cluster in a variety of ways. There are situations where having the business logic as part of your data queries can also be beneficial. SQL++ supports this with User Defined Functions [&hellip;]<\/p>\n","protected":false},"author":80878,"featured_media":13093,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2294,1816,8683,9327,9139,1812],"tags":[1543,8911],"ppma_author":[9543],"class_list":["post-13092","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","category-couchbase-server","category-geospatial","category-javascript","category-python","category-n1ql-query","tag-javascript","tag-udf"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.0 (Yoast SEO v26.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Creating Python and JavaScript User Defined Functions For Geospatial Queries - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"Create User Defined Functions UDFs in Python and JavaScript to run geospatial queries in Couchbase Analytics and SQL++\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating Python and JavaScript User Defined Functions For Geospatial Queries\" \/>\n<meta property=\"og:description\" content=\"Create User Defined Functions UDFs in Python and JavaScript to run geospatial queries in Couchbase Analytics and SQL++\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-04-20T17:22:45+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:34:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1920\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Nithish Raghunandanan\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nithish Raghunandanan\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\"},\"author\":{\"name\":\"nithishr\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c5a843d75ad78b5b698f59ca6d123af2\"},\"headline\":\"Creating Python and JavaScript User Defined Functions For Geospatial Queries\",\"datePublished\":\"2022-04-20T17:22:45+00:00\",\"dateModified\":\"2025-06-14T06:34:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\"},\"wordCount\":1127,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg\",\"keywords\":[\"javascript\",\"User Defined Function (UDF)\"],\"articleSection\":[\"Couchbase Analytics\",\"Couchbase Server\",\"Geospatial\",\"JavaScript\",\"Python\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\",\"name\":\"Creating Python and JavaScript User Defined Functions For Geospatial Queries - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg\",\"datePublished\":\"2022-04-20T17:22:45+00:00\",\"dateModified\":\"2025-06-14T06:34:37+00:00\",\"description\":\"Create User Defined Functions UDFs in Python and JavaScript to run geospatial queries in Couchbase Analytics and SQL++\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg\",\"width\":2560,\"height\":1920,\"caption\":\"Create user defined functions in Python and JavaScript\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Creating Python and JavaScript User Defined Functions For Geospatial Queries\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c5a843d75ad78b5b698f59ca6d123af2\",\"name\":\"nithishr\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/63270a592008f9080fe48b7652fe559f\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/03\/image-4.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/03\/image-4.png\",\"caption\":\"nithishr\"},\"description\":\"Nithish is an engineer who loves to build products that solve real-world problems in short spans of time. He has experienced different areas of the industry having worked in diverse companies in Germany and India. Apart from work, he likes to travel and interact and engage with the tech community through Meetups &amp; Hackathons. In his free time, he likes to try stuff out by hacking things together.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/nithishr\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Creating Python and JavaScript User Defined Functions For Geospatial Queries - The Couchbase Blog","description":"Create User Defined Functions UDFs in Python and JavaScript to run geospatial queries in Couchbase Analytics and SQL++","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/","og_locale":"en_US","og_type":"article","og_title":"Creating Python and JavaScript User Defined Functions For Geospatial Queries","og_description":"Create User Defined Functions UDFs in Python and JavaScript to run geospatial queries in Couchbase Analytics and SQL++","og_url":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/","og_site_name":"The Couchbase Blog","article_published_time":"2022-04-20T17:22:45+00:00","article_modified_time":"2025-06-14T06:34:37+00:00","og_image":[{"width":2560,"height":1920,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg","type":"image\/jpeg"}],"author":"Nithish Raghunandanan","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Nithish Raghunandanan","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/"},"author":{"name":"nithishr","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c5a843d75ad78b5b698f59ca6d123af2"},"headline":"Creating Python and JavaScript User Defined Functions For Geospatial Queries","datePublished":"2022-04-20T17:22:45+00:00","dateModified":"2025-06-14T06:34:37+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/"},"wordCount":1127,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg","keywords":["javascript","User Defined Function (UDF)"],"articleSection":["Couchbase Analytics","Couchbase Server","Geospatial","JavaScript","Python","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/","url":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/","name":"Creating Python and JavaScript User Defined Functions For Geospatial Queries - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg","datePublished":"2022-04-20T17:22:45+00:00","dateModified":"2025-06-14T06:34:37+00:00","description":"Create User Defined Functions UDFs in Python and JavaScript to run geospatial queries in Couchbase Analytics and SQL++","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/04\/couchbase-analytics-sql-user-defined-functions-scaled.jpg","width":2560,"height":1920,"caption":"Create user defined functions in Python and JavaScript"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/creating-python-and-javascript-user-defined-functions-for-geospatial-queries\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Creating Python and JavaScript User Defined Functions For Geospatial Queries"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c5a843d75ad78b5b698f59ca6d123af2","name":"nithishr","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/63270a592008f9080fe48b7652fe559f","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/03\/image-4.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/03\/image-4.png","caption":"nithishr"},"description":"Nithish is an engineer who loves to build products that solve real-world problems in short spans of time. He has experienced different areas of the industry having worked in diverse companies in Germany and India. Apart from work, he likes to travel and interact and engage with the tech community through Meetups &amp; Hackathons. In his free time, he likes to try stuff out by hacking things together.","url":"https:\/\/www.couchbase.com\/blog\/author\/nithishr\/"}]}},"authors":[{"term_id":9543,"user_id":80878,"is_guest":0,"slug":"nithishr","display_name":"Nithish Raghunandanan","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/03\/image-4.png","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/03\/image-4.png"},"author_category":"","last_name":"Raghunandanan","first_name":"Nithish","job_title":"","user_url":"","description":"Nithish is an engineer who loves to build products that solve real-world problems in short spans of time. He has experienced different areas of the industry having worked in diverse companies in Germany and India. Apart from work, he likes to travel and interact and engage with the tech community through Meetups & Hackathons. In his free time, he likes to try stuff out by hacking things together."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/13092","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/80878"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=13092"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/13092\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13093"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=13092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=13092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=13092"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=13092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}