3

I am trying to look for ignored questions and try to answer them or give them attention. I need a way to search for unclosed, unanswered, and uncommented questions. Is there a way to go about doing such a search?

2

3 Answers 3

5

Stack Exchange's search functionality doesn't have a comments:0 or similar filter, so that won't work. A crude way is to look for Tumbleweed badges; they are awarded to similar questions, but could be answered/commented after the badge has been earned. Because you can only earn the badge once, and the question may not have any up- and downvotes, you might miss some questions.

I've constructed a SEDE query to look for them. The view count is another measure for neglectance, so I've used it for sorting. The top hits on Chemistry.SE are these questions:

For reference, here is the complete query:

SELECT Id AS [Post Link], CreationDate, Score, ViewCount
  FROM Posts
  WHERE PostTypeId = 1 -- questions
    AND AnswerCount = 0
    AND CommentCount = 0
    AND ClosedDate IS NULL
  ORDER BY ViewCount

(thanks @ifajra for the suggestion)

Note that SEDE is updated once a week, on Sunday morning, so the questions might have answers or comments by now.

3
  • Thanks for making this query. I'd like to learn to make my own queries in the future, where can I learn to do that? Aug 19, 2017 at 15:49
  • Do you know SQL? If you do, it's pretty easy; there's a description of the data model elsewhere on Meta Stack Exchange. I can't find it right now, I'm on mobile.
    – Glorfindel Mod
    Aug 19, 2017 at 15:52
  • 1
    @Unitato It's here: meta.stackexchange.com/q/2677/295232
    – Glorfindel Mod
    Aug 19, 2017 at 16:01
4

You can use the following snippet to select a site and then click start to list questions with no-answers. It is based on the StackAPI no-answer-questions. Using the StackAPI instead of SEDE guarantees you always look at the most recent data, not data that can be stale for up to 7 days.

It filters out questions with a comment count < 2 because for some reason comment_count is often 1 when there are no visible comments. It loads 100 questions after which you can click load next to fetch the next batch of 100 questions.

(function() {
    'use strict';

    var currentSite, currentPage = 1;
 
    // build api url for an endpoint and its optional parameters
    function apiBuilder(endpoint, params) {
        var url = 'https://api.stackexchange.com/2.2/',
            urlPath = url + endpoint;
        params.key ='Kdg9mxpgwALz)u5ubehUFw((';
        if (params !== undefined)  {
            var query = [];
            for(var prop in params) {
                if (params.hasOwnProperty(prop)) {
                    query.push( prop + '=' + encodeURI(params[prop]));
                }
            }
            urlPath = urlPath + '?' + query.join('&');
        }
        return urlPath;
    }

    // build url for /sites api endpoint
    function apiSitesBuilder() {
        return apiBuilder(
            'sites', 
            {
                pagesize: 500,
                filter: '!*l7am7*mGv_Xmq-k..iQsWPn'
            });
    }

    // build url for /Question/Unanswered endpoint
    function apiQuestionBuilder(site, page) {
        return apiBuilder(
            'questions/no-answers', 
            {
                site: site,
                order: 'desc',
                page: page,
                pagesize: 100,
                sort: 'activity',
                filter: '!*7PmgCBkOPC0W(BajiIL1.9t)Azg'
            });
    }

    // do a get on the API for the given url
    // and invoke the callback with the JSON result
    function API () {

        var backlog = [],
            getfunction;

        // simply push the params on the queue
        function cacheget(url, callback) {
            backlog.push({ url: url, callback: callback});
        }

        // this makes the actual xhr call
        function realget(url, callback) {
            var xhr = new XMLHttpRequest();

            // handles pending calls by invoking realget
            // and resetting the getfunction when 
            // the backlog is cleared
            function handleBacklog() {
                var item = backlog.shift();
                if (item !== undefined) {
                    console.log('from cache');
                    // handle this single item
                    realget(item.url, item.callback);
                } 
                if (backlog.length === 0) {
                    // if the backlog is empty 
                    // use realget for the next call
                    getfunction = realget;
                }
            }

            xhr.addEventListener('error', function () {
                console.log(xhr.status);
            });

            xhr.addEventListener('load', function () {
                var response = JSON.parse(xhr.responseText);
                var backoff = response.backoff || 0;
                // backoff received
                if (backoff > 0) {
                    // start caching calls
                    console.log('backoff recv');
                    getfunction = cacheget;
                }
                if (response.error_id === 502) {
                    console.log(reponse.error_message);
                    getfunction = cacheget;
                    backoff = 120;
                }
                // process pending backlog
                setTimeout(handleBacklog, backoff * 1000);
                // invoke the callback
                callback(response);
            });
            xhr.open('GET', url);
            xhr.send();
        }

        // calls either xhr or the cache
        function get(url, callback)
        {
            getfunction(url, callback);
        }

        // initially we start with a realget
        getfunction = realget;

        // return the public api
        return {
            get: get
        };
    }

    var SEApi = new API(); // keep an instance
      
    function createQuestion(item) {
      var anchor = document.createElement('a'), 
          div = document.createElement('div');
      anchor.href = item.link;
      anchor.innerHTML = item.title;
      anchor.title = 'upvotes: ' + item.up_vote_count;
      div.appendChild(anchor);
      return div;
    }
     
    // what we see for a question 
    function handleQuestions(items) {
      var result = document.getElementById('result'), added = false;
      items.forEach(function(item) {
        if (item.comment_count && 
            item.comment_count < 2 &&
            item.locked_date === undefined) {
          result.appendChild(createQuestion(item));
          added = true;
        }
      });
      return added;
    }
   
    // get question with no answers 
    function getUnanswered(site) {
      // call the api
      SEApi.get(apiQuestionBuilder(site, currentPage) , function(data) {
         currentPage = data.has_more === false ? -1 : (currentPage + 1);
         if (data.has_more) {
            document.getElementById('go').textContent='Load next';
         } else {
            document.getElementById('go').textContent='No more questions';
         }
         if (data && data.items) {
           // in case no question were found at all ...
           if (!handleQuestions(data.items)) {
              // .. load the next page immediately
              getUnanswered(site);
           }
         }
      });
    }

    // load next page
    function paging() {
      if (currentPage === -1 ) return;
      var site = document.getElementById('site'); 
      getUnanswered(site.value);
    }

    // change a site
    function change() {
       var site = document.getElementById('site'), 
           img = document.getElementById('logo'), 
           result; 
       result = document.getElementById('result');
       while (result.firstChild) {
          result.removeChild(result.firstChild);
       }
       currentPage = 1;
       if (site.value !== '0') {
         currentSite = site.value
         site.childNodes.forEach(
           function(option) {
             if (option.value === site.value) {
               img.src = option.getAttribute('data-icon');
               img.style.display = 'inline';
             }
           }
         );
         getUnanswered(site.value);
       } else {
         img.style.display = 'none';
         document.getElementById('go').textContent='Start ...';
       }
    }
 
    function bindPager() {
      var pager = document.getElementById('pager'),
          select = document.getElementById('site');
      pager.addEventListener('click', paging);
      select.addEventListener('change', change);
    }
   
    function siteOption(site) {
       var option = document.createElement('option');
       option.value = site.api_site_parameter;
       option.setAttribute('data-icon', site.icon_url);
       option.innerHTML = site.name;
       return option;
    }

    // fill sites
    function fillSites(items) {
        var i, site, site = document.getElementById('site');
        items.forEach(function(item){
           site.appendChild(siteOption(item));
        });
        return null;
    }

    function error(msg) {
       var err = document.getElementById('error');
       err.textContent = msg;
    }

    SEApi.get(apiSitesBuilder(), function (data) {
        if (data.items && data.items.length) {
            fillSites(data.items);
            bindPager();
        } else {
           error('no sites');
        }
    });
})();
#go 
{
  text-align: center;
  padding-left: 50px;
  padding-right: 50px;
  padding-top: 5px;
  padding-bottom: 5px;
  background-color:blue;
  color: white;
  border-radius: 4px;
  cursor: pointer;
}
#pager{margin-top: 10px;}
#logo{width: 1em; height: 1em;padding-left:4px}
<div id="siteselect">
<label for="site">Site:
<select id="site">
<option value="0">Select a site</option>
</select></label><span><img id="logo"/></span>
</div>
<div id="error">
</div>
<div id="result">
</div>
<div id="pager">
<span id="go">Start ...</span>
</div>

6
  • +1 Although, it does list all the ghosts/shells left behind after merging questions.
    – NVZ
    Aug 20, 2017 at 16:04
  • @NVZ I changed the sort to active/desc and I'm now checking if a post is locked, and if so skip it as well. Also fixed the HTML encoding bugs. Thanks for reporting
    – rene
    Aug 20, 2017 at 20:36
  • Why doesn't this call to the API return as rich of JSON data as the link you put at the beginning of this answer? I was trying to modify your code to help me filter on "item.tags," but that's not in the dataset.all "item" seems to have are comment_count, up_vote_count, last_activity_date, question_id, link, & title.
    – k..
    Jan 4, 2019 at 16:23
  • @k.. there is a filter on it, by the looks of it. So if you get rid of filter: '!*7PmgCBkOPC0W(BajiIL1.9t)Azg' you might have more data, with the risk of having to backoff more often.
    – rene
    Jan 4, 2019 at 16:27
  • I was starting to play with that, but just commenting that out (and the preceding line's comma) kills the whole thing (makes no data return), as does replacing it with filter: 'default'
    – k..
    Jan 4, 2019 at 16:33
  • Okay, got it. Went to api.stackexchange.com/docs/no-answer-questions, played around with adding URL parameters to it until it was api.stackexchange.com/docs/…!*7PmgCBkOPC0W(BajiIL1.9t)Azg, then clicked "Edit" by the filter and added "tags" and grabbed the name of the new filter (!Pw)kHH1BI3aQjg4(GDU3spgT7lYocp). Works now!
    – k..
    Jan 4, 2019 at 16:42
0

Getting unclosed and unanswered is easy:

https://chemistry.stackexchange.com/search?q=answers%3A0+closed%3Ano

but to look for uncommented I think you would need to write/find an SQL query for the Stack Exchange Data Explorer.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .