Searching for users on custom fields

Plugin Development
  • I've added a custom field to the users of the forum by using the "filter:user.custom_fields" hook in a custom plugin, which is an awesome feature.

    The only problem I'm finding is I want to be able to search for users using this field, but I can't figure out how to use 'users.js' to achieve this. Is this possible with the current code?

    My alternative is to create another connection to the MongoDb, which seems a bit dirty, but it's what I'll do in the mean time.

    Any help would be great!

  • It looks like you can do this using User.search(), but it's a little hard for me to follow, my guess as to what your search object would be is:

    {
    sortBy: 'yourfield',
    pagination: false,
    filterBy: [
      {field: 'yourfield', type:'=', value:'thevalueyouwant'},
      {repeat for every value you want}
    ]
    }
    

    That should give you data.users, which is an array of userData objects the match your filters and are sorted by yourfield.

  • Thanks @yariplus.
    Hadn't seen this response until just now!
    🙂

  • @snodejoke

    Hey, yeah. I've been meaning to reply as well. What I typed above was actually and older 0.6.0 way of searching, and it doesn't actually work the way you want anyway.

    From what I can see, there is no way to search for custom fields using users.js

    It seems the proper way of doing would be to add a sorted set value when you create the field. If the field is a number, something like db.sortedSetAdd('users:yourfield', yourfield, uid, callback) then lookup with db.getSortedSetRangeByScore('users:yourfield', 0, count, min, max, callback), that's how I do it in my plugins now.

    If it's not a number, you need to store it as db.sortedSetAdd('yourfield:sorted', yourfield + ':' + uid, callback) then lookup with db.getSortedSetRangeByLex('yourfield:sorted', min, max, 0, count, callback)

    Here's how I sorted a custom field on my forum without creating a sortedset if you're interested:

    // Get all uids
    db.getSortedSetRange('users:joindate', 0, -1, function (err, uids) {		
    	// Get their custom_field
    	User.getMultipleUserFields(uids, ['uid', custom_field], function (err, users) {
    		// Sort by custom_field
    		async.sortBy(users, function (user, next) {
    			return next(null, user.custom_field);
    		}, function (err, results) {
    			console.log(results);
    		});
    	});
    });
    

    If not all users have the field, you can use the 'filter:users.get' hook to filter user results to only users that have the field, like I had to do.

    Hooks.filterUsersGet = function (users, next) {
    	// If 'custom_field' isn't in the results, don't filter.
    	if (users && users[0] && users[0].custom_field !== void 0) {
    		// Filter it out if it's null.
    		async.filter(users, function (user, next) {
    			return next(user.custom_field !== null);
    		}, function (results) {
    			next(null, results);
    		});
    	}else{
    		next(null, users);
    	}
    };
    

    Result:

    [ { uid: '18', uuid: '069a79f444e94726a5befca90e38aaf5' },
      { uid: '4', uuid: '294ecf637f1242c6a95d9cf8cc6da3ef' },
      { uid: '3', uuid: '32a46cc646d64ffea4da962692858288' },
      { uid: '5', uuid: '621ad5087ed448dd92dbc83950a222d9' },
      { uid: '17', uuid: 'a85e5f36dc5e465d9c86c6ad88912e99' },
      { uid: '1', uuid: 'f19cb1605bc24838835a07757d60ce80' } ]
    

Suggested Topics


  • 0 Votes
    1 Posts
    470 Views
    This is just a little snippet.

    This is about the question How can I add custom data to a post? a small tutorial

    How to add custom data permanently to a post It will be saved into the object:

    You need the following hook:

    { "hook": "filter:post.create", "method": "postCreate" }

    This hook is fired, when a Post is created. So it contains RAW Data.

    A filter:hook like "hook": "filter:post.create" can be edited before beeing proceeded.

    plugin.postCreate = function(data, callback){ // Edit data here callback(null, data); }

    You can access all Data you can work with via the data object.

    All those filter-hooks needs callbacks. The callback contains the modified / added / removed data.

    Whats inside the data object?

    The data object contains two main objects.

    this.post this.data post: { pid: 259, uid: 2, tid: 111, content: '### This is just a little snippet.', timestamp: 1617150411838 }, data: { uuid: '7277s31-6d23-43sa-1284-ad27e42yx879', title: 'How to add custom data to post serverside - in a nutshell', content: '### This is just a little snippet.', thumb: '', cid: '2', tags: [], uid: 2, req: { [...] }, timestamp: 1617150411838, fromQueue: false, tid: 111, ip: '111.123.2123.21', isMain: true } }

    With all the data you can work with. But only this.post is directly effected (lol) to the post Object.
    If you add data here. It will be attached to the post forever and you can access it any time. Even after plugin disable.

    So now add custom data:

    plugin.postCreate = function(data, callback){ // adds data **PERMANENT** to post // before any other procession -> RAW DATA (markdown) //data.post.myData = "directly effected to post you can work with it in next step"; //data.data.myData = "other data for other things I don't know"; var myData = {}; myData.name = "Schmock"; myData.signature = "raz0rn"; // Stick myData to post object data.post.myData = myData; // Debug? // console.log("POST CREATE", data); // finish the process() - passes on modified data callback(null, data); }

    So myData has added to post:

    post: { pid: 259, uid: 2, tid: 111, content: '### This is just a little snippet.', timestamp: 1617150411838, myData: { name = "Schmock", signature = "raz0rn", } }

    The data is stored. Everybody is happy.

    dance minions

    How to add dynamic data before render a post in template It wont be saved to the object. You can use this for dynamic things or logic before rendering the page.:

    You need the following hook:

    { "hook": "filter:topics.addPostData", "method": "addPostData" }

    This hook is fired before engine renders the template.
    It also needs a callback because its a filter-hook.

    plugin.addPostData = function(data, callback){ // modify data temporarily before it gets passed on to next step callback(null, data); }

    Same thing as above. Only the hook is different. And the data we are changing is temporarily.
    Data contains all data we can use for the dynamicness lol: .

    plugin.addPostData = function(data, callback){ // You can work with pre-parsed and already saved data .... // or put in something very flexible without saving to db like jquery-like dynamic etc etc // Debug? // console.log("addPostData?", data) var _posts = data.posts; _posts.forEach(function(post){ if(post.myData){ // add data to post if "myData" is there post.content = "THIS POST HAS MY OWN DATA -> CONTENT IS OVERWRITTEN"; } // this here affects all posts post.user.signature = "Ihr seid alle Schmocks!"; }); // Overwrite data and pass modified data on to the template engine data.posts = _posts; callback(null, data); }

    Now you can work with posts like a boss.

    Bildschirmfoto 2021-03-31 um 03.10.32.png

    dab

    Thanks and bye

    Important Note:

    Remind, that myData is available via API.

    https://nodebb.development.fail/api/topic/114/new-post

    returns your added data

    "content": "THIS POST AS MY OWN DATA -> CONTENT IS OVERWRITTEN", "myData": { "name": "Schmock", "signature": "raz0rn" }
  • 0 Votes
    14 Posts
    3k Views

    @baris
    no, just I got an empty pull down menu when I clicked Topic Tools.

    Today I tried again, and got the pull down popolated.

    Strange....

  • 0 Votes
    4 Posts
    2k Views

    @julian There didn't appear to be a way of managing this number plus I assumed there are already lots of things node already does to modify this number.

    I wanted completely control of it, including the ability to "spend" it on things down the road.

  • 0 Votes
    3 Posts
    2k Views

    For anyone looking to do this for a plugin, it's easy enough using getObjectValues()

    var db = require.main.require('./src/database') var User = require.main.require('./src/user') db.getObjectValues('steamid:uid', function (err, uids) { if (err) return console.log(err) uids = uids.sort().filter(function(item, pos, ary) { return !pos || item != ary[pos - 1] }) User.getUsersFields(uids, ['username', 'email', 'steamid', 'profileurl'], function (err, users) { if (err) return console.log(err) users.forEach(function (user) { // Do a thing here. console.dir(user) }) }) })
  • 0 Votes
    2 Posts
    2k Views

    On the server, you can do

    var groups = require.main.require('./src/groups'); groups.getUserGroups([1] /*array of uids*/, function(err, userGroups){ if (err) return; // Returns an array of an array of group data. console.log(userGroups[0]); // Prints an array of groups for uid 1 });

    on the client, you can get a list of visible groups by doing:

    $.getJSON('/api/user/USERSLUG/groups', function (data) { // Returns an object with a 'groups' property, an array of visible group data. console.log(data.groups); });