@@ -674,6 +674,39 @@ func (s *Store) GetBulk(keys ...string) ([][]byte, error) {
674
674
return allValues , nil
675
675
}
676
676
677
+ // GetBulkAsRawMap fetches the values associated with the given keys and returns the documents (as maps).
678
+ // If no data exists under a given key, then nil is returned for that value. It is not considered an error.
679
+ // Depending on the implementation, this method may be faster than calling Get for each key individually.
680
+ // If any of the given keys are empty, then an error will be returned.
681
+ func (s * Store ) GetBulkAsRawMap (keys ... string ) ([]map [string ]interface {}, error ) {
682
+ if len (keys ) == 0 {
683
+ return nil , errors .New ("keys slice must contain at least one key" )
684
+ }
685
+
686
+ for _ , key := range keys {
687
+ if key == "" {
688
+ return nil , errors .New ("key cannot be empty" )
689
+ }
690
+ }
691
+
692
+ ctxWithTimeout , cancel := context .WithTimeout (context .Background (), s .timeout )
693
+ defer cancel ()
694
+
695
+ cursor , err := s .coll .Find (ctxWithTimeout , bson.M {"_id" : bson.D {
696
+ {Key : "$in" , Value : keys },
697
+ }})
698
+ if err != nil {
699
+ return nil , fmt .Errorf ("failed to run Find command in MongoDB: %w" , err )
700
+ }
701
+
702
+ allValues , err := s .collectBulkGetResultsAsRawMap (keys , cursor )
703
+ if err != nil {
704
+ return nil , err
705
+ }
706
+
707
+ return allValues , nil
708
+ }
709
+
677
710
// Query does a query for data as defined by the documentation in storage.Store (the interface).
678
711
// This implementation also supports querying for data tagged with multiple tag name + value pairs (using AND logic).
679
712
// To do this, separate the tag name + value pairs using &&. You can still omit one or both of the tag values
@@ -691,12 +724,12 @@ func (s *Store) Query(expression string, options ...storage.QueryOption) (storag
691
724
return & Iterator {}, errInvalidQueryExpressionFormat
692
725
}
693
726
694
- filter , err := prepareFilter (strings .Split (expression , "&&" ), false )
727
+ filter , err := PrepareFilter (strings .Split (expression , "&&" ), false )
695
728
if err != nil {
696
729
return nil , err
697
730
}
698
731
699
- findOptions := s .createMongoDBFindOptions (options )
732
+ findOptions := s .CreateMongoDBFindOptions (options )
700
733
701
734
ctxWithTimeout , cancel := context .WithTimeout (context .Background (), s .timeout )
702
735
defer cancel ()
@@ -933,6 +966,30 @@ func (s *Store) collectBulkGetResults(keys []string, cursor *mongo.Cursor) ([][]
933
966
return allValues , nil
934
967
}
935
968
969
+ func (s * Store ) collectBulkGetResultsAsRawMap (keys []string , cursor * mongo.Cursor ) ([]map [string ]interface {}, error ) {
970
+ allValues := make ([]map [string ]interface {}, len (keys ))
971
+
972
+ ctxWithTimeout , cancel := context .WithTimeout (context .Background (), s .timeout )
973
+ defer cancel ()
974
+
975
+ for cursor .Next (ctxWithTimeout ) {
976
+ key , value , err := getKeyAndRawMapFromMongoDBResult (cursor )
977
+ if err != nil {
978
+ return nil , fmt .Errorf ("failed to get value from MongoDB result: %w" , err )
979
+ }
980
+
981
+ for i := 0 ; i < len (keys ); i ++ {
982
+ if key == keys [i ] {
983
+ allValues [i ] = value
984
+
985
+ break
986
+ }
987
+ }
988
+ }
989
+
990
+ return allValues , nil
991
+ }
992
+
936
993
func (s * Store ) executeBulkWriteCommand (models []mongo.WriteModel , atLeastOneInsertOneModel bool ) error {
937
994
var attemptsMade int
938
995
@@ -993,7 +1050,8 @@ func (s *Store) executeBulkWriteCommand(models []mongo.WriteModel, atLeastOneIns
993
1050
}, backoff .WithMaxRetries (backoff .NewConstantBackOff (s .timeBetweenRetries ), s .maxRetries ))
994
1051
}
995
1052
996
- func (s * Store ) createMongoDBFindOptions (options []storage.QueryOption ) * mongooptions.FindOptions {
1053
+ // CreateMongoDBFindOptions converts the given storage options into MongoDB options.
1054
+ func (s * Store ) CreateMongoDBFindOptions (options []storage.QueryOption ) * mongooptions.FindOptions {
997
1055
queryOptions := getQueryOptions (options )
998
1056
999
1057
findOptions := mongooptions .Find ()
@@ -1261,6 +1319,25 @@ func getKeyAndValueFromMongoDBResult(decoder decoder) (key string, value []byte,
1261
1319
return data .Key , valueBytes , nil
1262
1320
}
1263
1321
1322
+ func getKeyAndRawMapFromMongoDBResult (decoder decoder ) (key string , doc map [string ]interface {}, err error ) {
1323
+ doc , errGetDataWrapper := getValueAsRawMapFromMongoDBResult (decoder )
1324
+ if errGetDataWrapper != nil {
1325
+ return "" , nil , fmt .Errorf ("failed to get data wrapper from MongoDB result: %w" , errGetDataWrapper )
1326
+ }
1327
+
1328
+ id , ok := doc ["_id" ]
1329
+ if ! ok {
1330
+ return "" , nil , fmt .Errorf ("no _id field in document" )
1331
+ }
1332
+
1333
+ key , ok = id .(string )
1334
+ if ! ok {
1335
+ return "" , nil , fmt .Errorf ("_id field in document is not a string" )
1336
+ }
1337
+
1338
+ return key , doc , nil
1339
+ }
1340
+
1264
1341
func getTagsFromMongoDBResult (decoder decoder ) ([]storage.Tag , error ) {
1265
1342
data , err := getDataWrapperFromMongoDBResult (decoder )
1266
1343
if err != nil {
@@ -1307,7 +1384,8 @@ func getQueryOptions(options []storage.QueryOption) storage.QueryOptions {
1307
1384
return queryOptions
1308
1385
}
1309
1386
1310
- func prepareFilter (expressions []string , isJSONQuery bool ) (bson.D , error ) {
1387
+ // PrepareFilter converts the expression into a MongoDB filter.
1388
+ func PrepareFilter (expressions []string , isJSONQuery bool ) (bson.D , error ) {
1311
1389
operands := make (bson.D , len (expressions ))
1312
1390
1313
1391
for i , exp := range expressions {
@@ -1332,6 +1410,14 @@ func prepareSingleOperand(expression string, isJSONQuery bool) (bson.E, error) {
1332
1410
return bson.E {}, err
1333
1411
}
1334
1412
1413
+ var key string
1414
+
1415
+ if isJSONQuery {
1416
+ key = splitExpression [0 ]
1417
+ } else {
1418
+ key = fmt .Sprintf ("tags.%s" , splitExpression [0 ])
1419
+ }
1420
+
1335
1421
if operator == "$lt" || operator == "$lte" || operator == "$gt" || operator == "$gte" {
1336
1422
value , err := strconv .Atoi (splitExpression [1 ])
1337
1423
if err != nil {
@@ -1343,14 +1429,6 @@ func prepareSingleOperand(expression string, isJSONQuery bool) (bson.E, error) {
1343
1429
{Key : operator , Value : value },
1344
1430
}
1345
1431
1346
- var key string
1347
-
1348
- if isJSONQuery {
1349
- key = splitExpression [0 ]
1350
- } else {
1351
- key = fmt .Sprintf ("tags.%s" , splitExpression [0 ])
1352
- }
1353
-
1354
1432
operand := bson.E {
1355
1433
Key : key ,
1356
1434
Value : filterValue ,
@@ -1368,7 +1446,7 @@ func prepareSingleOperand(expression string, isJSONQuery bool) (bson.E, error) {
1368
1446
}
1369
1447
1370
1448
operand := bson.E {
1371
- Key : fmt . Sprintf ( "tags.%s" , splitExpression [ 0 ]) ,
1449
+ Key : key ,
1372
1450
Value : filterValue ,
1373
1451
}
1374
1452
0 commit comments