Ben Haim Shani
Ben Haim Shani

Reputation: 265

Aerospike - Query on Map Keys

I have a question about Aerospike DB.

I have set of students, and each student (record key is StudentId), has a map (bin) of <CourseId, Grade>. I'm trying to create some queries, and I'm not sure what is the correct way to do it.

I have variable containing a List of <String> courseIds.

The queries that I want to create are:

  1. For each student, get all the courseIds that exists in the map and in the list.
  2. For each student, get all the courseIds that exist only in their map, and not in the list.

What is the best approach here? Should I use UDF?

Thanks.

Upvotes: 2

Views: 471

Answers (1)

Ronen Botzer
Ronen Botzer

Reputation: 7117

This is the kind of thing a record UDF is good for - extending functionality that doesn't yet exist in predicate filtering. The record UDF can take the bin name as the first argument, your list variable as its second argument, and an optional third argument for deciding whether this is an 'IN' or 'NOT IN', then iterate through it against the map of course IDs.

You can apply this record UDF to every record matched by a scan or query running against the set containing the students.

test.lua

function list_compare(rec, bin, l, not_in_l)
  if rec[bin] then
    local b = rec[bin]
    if (tostring(getmetatable(rec[bin])) == tostring(getmetatable(list()))) then
      iter = list.iterator
    elseif (tostring(getmetatable(rec[bin])) == tostring(getmetatable(map()))) then
      iter = map.values
    else
      return nil
    end
    local s = {}
    local l_keys = {}
    if (not_in_l ~= nil) then
      for v in list.iterator(l) do
        l_keys[v] = 1
      end
    end
    for i in list.iterator(l) do
      for v in iter(b) do
        if (not_in_l == nil) then
          if (i == v) then
            s[v] = 1
          end
        else
          if (i ~= v and not l_keys[v]) then
            s[v] = 1
          end
        end
      end
    end
    local keys = {}
    for k,v in pairs(s) do
      table.insert(keys, k)
    end
    table.sort(keys)
    return list(keys)
  end
end

In AQL:

$ aql
Aerospike Query Client
Version 3.15.1.2
C Client Version 4.3.0
Copyright 2012-2017 Aerospike. All rights reserved.
aql> register module './test.lua'
OK, 1 module added.
aql> insert into test.demo (PK,i,s,m,l) values ('88',6,'six',MAP('{"a":2, "b":4, "c":8, "d":16}'),LIST('[2, 4, 8, 16, 32, 128, 256]'))
OK, 1 record affected.

aql> select * from test.demo where PK='88'
+---+-------+--------------------------------------+-------------------------------------+
| i | s     | m                                    | l                                   |
+---+-------+--------------------------------------+-------------------------------------+
| 6 | "six" | MAP('{"a":2, "b":4, "c":8, "d":16}') | LIST('[2, 4, 8, 16, 32, 128, 256]') |
+---+-------+--------------------------------------+-------------------------------------+
1 row in set (0.001 secs)

aql> execute test.list_compare("l", LIST('[1,2,3,4]')) on test.demo where PK='88'
+----------------+
| list_compare   |
+----------------+
| LIST('[2, 4]') |
+----------------+
1 row in set (0.002 secs)

aql> execute test.list_compare("l", LIST('[1,2,3,4]'),1) on test.demo where PK='88'
+-------------------------------+
| list_compare                  |
+-------------------------------+
| LIST('[8, 16, 32, 128, 256]') |
+-------------------------------+
1 row in set (0.001 secs)

aql> execute test.list_compare("m", LIST('[1,2,3,4]')) on test.demo where PK='88'
+----------------+
| list_compare   |
+----------------+
| LIST('[2, 4]') |
+----------------+
1 row in set (0.001 secs)

aql> execute test.list_compare("m", LIST('[1,2,3,4]'), 1) on test.demo where PK='88'
+-----------------+
| list_compare    |
+-----------------+
| LIST('[8, 16]') |
+-----------------+
1 row in set (0.000 secs)

Upvotes: 2

Related Questions