diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp
index 0c57aad2f..93de7b7d2 100644
--- a/src/query/interpret/awesome_memgraph_functions.cpp
+++ b/src/query/interpret/awesome_memgraph_functions.cpp
@@ -599,7 +599,7 @@ TypedValue ValueType(const TypedValue *args, int64_t nargs, const FunctionContex
 
 // TODO: How is Keys different from Properties function?
 TypedValue Keys(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
-  FType<Or<Null, Vertex, Edge>>("keys", args, nargs);
+  FType<Or<Null, Vertex, Edge, Map>>("keys", args, nargs);
   auto *dba = ctx.db_accessor;
   auto get_keys = [&](const auto &record_accessor) {
     TypedValue::TVector keys(ctx.memory);
@@ -624,11 +624,64 @@ TypedValue Keys(const TypedValue *args, int64_t nargs, const FunctionContext &ct
   const auto &value = args[0];
   if (value.IsNull()) {
     return TypedValue(ctx.memory);
-  } else if (value.IsVertex()) {
+  }
+  if (value.IsVertex()) {
     return get_keys(value.ValueVertex());
-  } else {
+  }
+  if (value.IsEdge()) {
     return get_keys(value.ValueEdge());
   }
+
+  // map
+  TypedValue::TVector keys(ctx.memory);
+  for (const auto &[string_key, value] : value.ValueMap()) {
+    keys.emplace_back(string_key);
+  }
+  return TypedValue(std::move(keys));
+}
+
+TypedValue Values(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
+  FType<Or<Null, Vertex, Edge, Map>>("keys", args, nargs);
+
+  auto get_values = [&](const auto &record_accessor) {
+    TypedValue::TVector values(ctx.memory);
+    auto maybe_props = record_accessor.Properties(ctx.view);
+    if (maybe_props.HasError()) {
+      switch (maybe_props.GetError()) {
+        case storage::Error::DELETED_OBJECT:
+          throw QueryRuntimeException("Trying to get keys from a deleted object.");
+        case storage::Error::NONEXISTENT_OBJECT:
+          throw query::QueryRuntimeException("Trying to get keys from an object that doesn't exist.");
+        case storage::Error::SERIALIZATION_ERROR:
+        case storage::Error::VERTEX_HAS_EDGES:
+        case storage::Error::PROPERTIES_DISABLED:
+          throw QueryRuntimeException("Unexpected error when getting keys.");
+      }
+    }
+    for (const auto &[key, value] : *maybe_props) {
+      values.emplace_back(std::move(value));
+    }
+    return TypedValue(std::move(values));
+  };
+
+  const auto &value = args[0];
+  if (value.IsNull()) {
+    return TypedValue(ctx.memory);
+  }
+  if (value.IsVertex()) {
+    return get_values(value.ValueVertex());
+  }
+  if (value.IsEdge()) {
+    return get_values(value.ValueEdge());
+  }
+
+  // map
+  TypedValue::TVector values(ctx.memory);
+  for (const auto &[string_key, value] : value.ValueMap()) {
+    values.emplace_back(value);
+  }
+
+  return TypedValue(std::move(values));
 }
 
 TypedValue Labels(const TypedValue *args, int64_t nargs, const FunctionContext &ctx) {
@@ -1269,7 +1322,7 @@ std::function<TypedValue(const TypedValue *, int64_t, const FunctionContext &ctx
   if (function_name == "TYPE") return Type;
   if (function_name == "VALUETYPE") return ValueType;
 
-  // List functions
+  // List, map functions
   if (function_name == "KEYS") return Keys;
   if (function_name == "LABELS") return Labels;
   if (function_name == "NODES") return Nodes;
@@ -1277,6 +1330,7 @@ std::function<TypedValue(const TypedValue *, int64_t, const FunctionContext &ctx
   if (function_name == "RELATIONSHIPS") return Relationships;
   if (function_name == "TAIL") return Tail;
   if (function_name == "UNIFORMSAMPLE") return UniformSample;
+  if (function_name == "VALUES") return Values;
 
   // Mathematical functions - numeric
   if (function_name == "ABS") return Abs;