Skip to content

LINQ query with predicate #684

Open
Open
@j82w

Description

@j82w

Describe the bug
A user can do the following code. This is very bad because it is doing a synchronous read feed. IQueryable.Where does not support taking in a func. Only the IEnumerable.Where supports func. This will cause the SDK will read all the items from the container so it returns an IEnumerable. The IEnumerable.Where then can be ran over all the items on the client side. This very inefficient and consume a lot of RUs.

List<Family> families = new List<Family>();
            Func<Family, bool> v = new Func<Family, bool>(x => true);
            // SQL
            IEnumerable<Family> setIterator = container.GetItemLinqQueryable<Family>(true).Where(v).AsEnumerable<Family>();
                foreach (Family item in setIterator)
                {
                    families.Add(item);
                }
            
            Assert("Expected two families", families.ToList().Count == 2);

The user should pass in an expression rather than a function. The expression can be parsed into a SQL query. This means all the filtering is done on Cosmos DB and only the required items are returned. The code should also be run asynchronously to avoid performance issue once the application starts to scale.

Expression<Func<Family, bool>> func = (family) => family.id != "test5";
IEnumerable<Family> results = await QueryHelper(container, func);
...
public async Task<IEnumerable<Family>> QueryHelper(Container container, Expression<Func<Family, bool>> predicate)
        {
            IQueryable<Family> queryable = container.GetItemLinqQueryable<Family>().Where(predicate);

            FeedIterator<Family> feedIterator = queryable.ToFeedIterator();
            List<Family> familyResults = new List<Family>();
            while (feedIterator.HasMoreResults)
            {
                familyResults.AddRange(await feedIterator.ReadNextAsync());
            }

            return familyResults;

There are 2 solutions I see that can help prevent other users from hitting this.

  1. Add a request option that has to be enabled to support sync read feed.
  2. Implement a custom ICosmosQueryable that is almost identical to the current IQueryable. The big difference is we can have an explicit ExecuteAsync to actually run the query. This would also allow the ability to support CountAsync and other aggregates.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions