Iterating in reverse Order - Empty Content
rebootcode opened this issue · comments
I am trying to Iterate in Reverse Order, but every time, I set Reverse
to true
. It gives empty value.
Below is code -
txn := db.NewTransaction(false)
defer txn.Discard()
err = db.View(func(txn *badger.Txn) error {
DefaultIteratorOptions := badger.DefaultIteratorOptions
DefaultIteratorOptions.Reverse = true
it = txn.NewIterator(DefaultIteratorOptions)
key := strconv.Itoa(t.Year()) + "-" + strconv.Itoa(int(t.Month())) + "-" + strconv.Itoa(int(t.Day()))
prefix := []byte(key)
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
k := item.Key()
v, err := item.ValueCopy([]byte(k))
if err != nil {
ctx.WriteString("Content not available")
return err
}
blogList, err := decodeBlog(v)
if err != nil {
fmt.Println("Error: decode: " + err.Error())
}
buffer.WriteString("My Content First")
}
})
When you seek for a key in reverse iterator, we find first key which is less than or equal to the seek key.
Say you have a list of keys
- "a:key1"
- "b:key2"
- "b:key3"
- "b:key4"
when you seek for "b:" in reverse mode and iterate you will see only key "a:key1" and since you are doing validForPrefix check you won't see any data.
If you want all values for that prefix in reverse mode you should seek for
prefixKey := append([]byte("prefix"), 0xFF)
Just be careful of the case where you have keys of the form "prefix", 0xff, ... some other bytes ...
.
When seeking to the initial iterator position, it would be more correct to seek to the prefix but with the last byte incremented. So if your prefix is "prefix"
, then you should seek to "prefiy"
. (Watch out for the case where the last byte in the prefix is 0xff... you'll have to do something a bit tricker to avoid edge cases then).
This whole thing seems a bit tricky for users to get right. Maybe we need a SeekAfter
method?
When you seek for a key in reverse iterator, we find first key which is less than or equal to the seek key.
Say you have a list of keys"a:key1"
"b:key2"
"b:key3"
"b:key4"
when you seek for "b:" in reverse mode and iterate you will see only key "a:key1" and since you are doing validForPrefix check you won't see any data.
If you want all values for that prefix in reverse mode you should seek for
prefixKey := append([]byte("prefix"), 0xFF)
Wow, I just missed the whole context. Isn't reverse suppose to iterate the value for key b
in reverse order like b:key4
, b:key3
, b:key2
?
I tried, prefixing 0xFF
too like below, yet i see empty results.
txn := db.NewTransaction(false)
defer txn.Discard()
err = db.View(func(txn *badger.Txn) error {
DefaultIteratorOptions := badger.DefaultIteratorOptions
DefaultIteratorOptions.Reverse = true
it = txn.NewIterator(DefaultIteratorOptions)
key := strconv.Itoa(t.Year()) + "-" + strconv.Itoa(int(t.Month())) + "-" + strconv.Itoa(int(t.Day()))
prefix := append([]byte(key), 0xFF)
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
k := item.Key()
v, err := item.ValueCopy([]byte(k))
if err != nil {
ctx.WriteString("Content not available")
return err
}
blogList, err := decodeBlog(v)
if err != nil {
fmt.Println("Error: decode: " + err.Error())
}
buffer.WriteString("My Content First")
}
})
Just right out of bat, I find this strange:
k := item.Key()
v, err := item.ValueCopy([]byte(k))
Reusing an internal byte slice from item would cause weird issues -- and the one you're seeing might be related. So, fix that, and then re-run the iterator. Also, have a look at the tests which do reverse iteration, and see how they achieve the same results.
@manishrjain, Ok, the only other option I see is:-
k := item.Key()
v, err := item.Value()
But I read in FAQ https://github.com/dgraph-io/badger#frequently-asked-questions, where it says, If writes are getting stuck, then it's better to use Use Item::ValueCopy instead of Item::Value when retrieving a value.
Is there any other hack around available where reuse can be fixed.
Update: Even after using item.Value()
the results are empty.
The new GetSequence
method is more easy to adopt for my requirement, I am switching my option to nextSequence
approach like an update here #346
Thanks