SOLVED find objects with wildcard


  • is it possible to retrieve all objects with a _key matching a regular expression? I know it is possible with MongoDB, but I'm not sure how to do it with NodeBB.

    I'm storing documents with the following key scheme:
    reputationLog:{userId}:{authorId}:{threadId}:{postId}

    What I want to do is, for example, retrieve all logs with userId=1 and threadId=4:
    db.getCollection('objects').find({_key:/reputationLog:1:.*:4:.*/})

    How can I do this with NodeBB? db.getObjects doesn't seem to be working like that.

    Thanks!


  • From having briefly looked at the code, db.GetObjects only accepts a whitelist of IDs to look up.
    I suppose you could submit a Pull Request, but if the same feature is not available in Redis then you are creating a feature that only exists in some of the supported storage systems, which increases complexity of the NodeBB project.

    It looks like NodeJS + MongoDB does support query by RegExp.
    My guess is that you would want to detect the data type of the first parameter passed into db.GetObjects similar to the following:

    re = new RegExp('.');
    'object' === typeof re && re instanceof RegExp;
    

  • Thank you @carbonphyber
    Not sure if Redis can do queries like that...
    I can change the keys too, but I don't know how can I store objects in a way that I can query them later like:

    • all objects with userId=x
    • all objects with authorId=x
    • all objects with threadId=x

    If there is a document structure that can be queried this way with existing NodeBB functions then I can change it.

  • Community Rep

    No way to do it with redis, without creating a separate set or sortedset. Look in user/create.js for how nbb does it, there's like 8+ sets created that track user object fields, like 'users:reputation' which relates users' uids with their reputation score. You need to query the wanted reputation scores with getSortedSetByScore() and send the resulting uid array to getObjects().

    You need to create sets like that one if you want to quickly query objects for a field value. Also, the object and the sets are not implicitly linked. Whenever the object field changes, you also need to update the set.


  • thanks @yariplus I think I now see how can I achieve it:
    I will have to create 3 sets in addition to the existing "main" object:

    • one with a key like: reputationLog:voter:{userId}
    • one with a key like: reputationLog:author:{authorId}
    • one with a key like: reputationLog:thread:{threadId}

    This way when I want to find all votes in a thread, I can query against the last set.
    If I want to retrieve all votes given to a certain user (author) then I would query the second set, and so on.
    Inside each set I would store all the information needed to finally create the "full" query (user, author, thread and post):
    reputationLog:{userId}:{authorId}:{threadId}:{postId}

    It is a bit messy, and sets would contain duplicated information. Also when a vote changes the data must be updated in all sets and also the "main" object.
    It's a pity I can't use MongoDB's full potential, that would have been much much easier!

    thanks again, I will try this later.


  • In case someone comes to this thread in the future, here is the solution I came up with: https://github.com/exo-do/nodebb-plugin-reputation-rules/blob/master/ReputationManager.js

    A main object and 3 sets as I said, nothing complex (in fact working with sets is pretty easy) but a bit confusing.
    When I save or update the main object I have to also call 3 times db.setAdd() or db.setRemove() depending on vote type (upvote, downvote or undo) but thats all.

    Thanks again for your help guys 😄

Suggested Topics

| |