MongoDB random results in C # LINQ

I am using the linq MongoDB driver to get results from a database

mymongocollection.AsQueryable().Where(x => x.Type == 1);

Now I would like to return 20 random entries from above. I searched but cannot find a suitable way to do this with LINQ. I prefer not to do this in memory, but in the database. I found that you can use MongoDB aggregation $sample, but I don't know how to translate it into LINQ (if possible).

+4
source share
4 answers

I assume that you are using the wrong namespace, for example using System.Linq;, which provides access to IQueryable.

using MongoDB.Driver.Linq;, MongoQueryable, sample aggregation

2.4.0 .

using MongoDB.Driver.Linq; 
collection.AsQueryable().Where(x => x.Type == 1).Sample(20); 

{aggregate([{ "$match" : { "Type" : 1 } }, { "$sample" : { "size" : NumberLong(20) } }])}

https://jira.mongodb.org/browse/CSHARP-1773

https://jira.mongodb.org/browse/CSHARP-1366

+6

LINQ. , mongo property, toList , .

, : N Linq

var result = MongoCollection
            .AsQueryable()
            .Where(x => x.Type == 1)
            .ToList()
            .OrderBy(x => Guid.NewGuid())
            .Take(20)
            .ToList();

, !

, db ( , ):

var result = MongoCollection
            .AsQueryable()
            .Where(x => x.Type == 1)
            .AsEnumerable()
            .OrderByDescending(x => Guid.NewGuid())
            .Take(20)
            .ToList();

, .

+1

.

var resultsCount = MongoCollection
                  .AsQueryable()
                  .Where(x => x.Type == 1)
                  .Count();

var randomSkip = (new Random()).Next(0, resultsCount - 20);

var result = MongoCollection
            .AsQueryable()
            .Where(x => x.Type == 1)
            .Skip(randomSkip)
            .Take(20)
            .ToList();
+1

,

:

var resultsCount = MongoCollection
  .AsQueryable()
  .Where(x => x.Type == 1)
  .Count();

:

var sampleSize = 10;
var rnd = new Random();
var indexes = Enumerable.Range(0, resultsCount-1);
var randomSet = indexes
  .OrderBy(r => rnd.NextDouble())
  .Take(sampleSize)
  .ToList();

zipping:

var result = MongoCollection
  .AsQueryable()
  .Where(x => x.Type == 1)
  .Zip(indexes, (x, y)=> Tuple.Create(x,y))
  .Where(tuple => randomSet.Any(r => r == tuple.Item2))
  .Take(sampleSize)       // for good measure, finish when all samples taken
  .Select(t => t.Item1)   // clear the indexes
  .ToList();

It should be efficient in terms of memory, but not so networked.

This is a test for Linqpad with simulated db elements:

var resultsCount = 30;
var sampleSize = 10;

// Create a random set of indexes
var rnd = new Random();
var indexes = Enumerable.Range(0, resultsCount-1);
var randomSet = indexes.OrderBy(r => rnd.NextDouble()).Take(sampleSize).ToList();
randomSet.OrderBy(r => r).Dump("Random set of indexes");

// Simulated resultset
// for convenience simulate db items from index set
var db = indexes.Select(x => "Result" + x.ToString());  

// The query
var sampleOfResults = 
  db.Zip(indexes, (x, y)=> Tuple.Create(x,y))
    .Where(tuple => randomSet.Any(r => r == tuple.Item2))
    .Take(sampleSize)       // for good measure, finish when all samples taken
    .Select(t => t.Item1);  // clear the indexes

sampleOfResults.ToList().Dump("Sample");
+1
source

Source: https://habr.com/ru/post/1687062/


All Articles