Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSHARP-4248: Allow collectionless $lookup with $documents. #1544

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

rstam
Copy link
Contributor

@rstam rstam commented Nov 14, 2024

No description provided.

@rstam rstam requested a review from sanych-sun November 14, 2024 20:55
@rstam rstam requested a review from a team as a code owner November 14, 2024 20:55
/// <notes>The Results property of <see cref="T:LookupResult{TSource,TDocument}"/> contains the matching foreign documents.</notes>
public static IQueryable<LookupResult<TSource, TDocument>> Lookup<TSource, TDocument, TField>(
this IQueryable<TSource> source,
Expression<Func<TSource, IEnumerable<TDocument>>> documents,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documents could also be a constant but the server allows the documents to be computed.

/// <typeparam name="TField">The type of the fields being compared.</typeparam>
/// <returns>An <see cref="T:IQueryable{LookupResult{TSource,TForeign}}"/> with the results of the Lookup.</returns>
/// <notes>The Results property of <see cref="T:LookupResult{TSource,TForeign}"/> contains the matching foreign documents.</notes>
public static IQueryable<LookupResult<TSource, TForeign>> Lookup<TSource, TForeign, TField>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 6 new overloads correspond to the 6 variations of $lookup supported by the server:

1: from with localField and foreignField
2. from with pipeline
3. from with localField and foreignField and pipeline (the "concise" syntax)
4. $documents with localField and foreignField
5. $documents with pipeline
6. $documents with localField and foreignField and pipeline (the "concise" syntax)

AstProject.Exclude("_id"));
var wrappedLocalSerializer = WrappedValueSerializer.Create("_local", localSerializer);

IMongoCollection foreignCollection = null;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The technique here is to optionally construct the pieces that make up the lookup and then build the AST at the end.

Not all pieces are present in all overloads of Lookup.


AstStage lookupStage = null;
IBsonSerializer resultSerializer = null;
if (method.Is(MongoQueryableMethod.LookupWithFromAndLocalFieldAndForeignField))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is where we start building the 6 variations of AST using the pieces that were created above.

context = context.WithSymbol(localSymbol);

var provider = new MongoQueryProvider<TDocument>(documentSerializer, session: null, options: null);
var queryable = new MongoQuery<TDocument, TDocument>(provider);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new way of creating an IQueryable that is not tied to any particular collection.

Most of the time an IQueryable is tied to a collection being queried (or possibly a database for some kinds of queries).

/// <typeparam name="TLocal">The type of the local documents.</typeparam>
/// <typeparam name="TResult">The type of the result values.</typeparam>
[BsonSerializer(typeof(LookupResultSerializer<,>))]
public struct LookupResult<TLocal, TResult>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class that is the result of a Lookup.

/// <summary>
/// The result values.
/// </summary>
public TResult[] Results { get; init; }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The results are either the TForeign documents or if a pipeline is provided then the TResult of the pipeline.

_pipelineInputSerializer = NoPipelineInputSerializer.Instance;
}

internal MongoQueryProvider(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New constructor to support LINQ queries that aren't tied to any collection or database.

@@ -23,6 +23,13 @@

namespace MongoDB.Driver
{
internal interface IMongoCollection
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally IMongoCollection<TDocument> would derive from IMongoColletion but that could be considered a breaking change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it is. Could you please add this to the TODO list for next major release? https://docs.google.com/document/d/1pGrELOhAvzXvavUDqIA-su0ic6wf2Mu6h20llrYj_VA

@@ -31,7 +31,7 @@

namespace MongoDB.Driver
{
internal sealed class MongoCollectionImpl<TDocument> : MongoCollectionBase<TDocument>
internal sealed class MongoCollectionImpl<TDocument> : MongoCollectionBase<TDocument>, IMongoCollection
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since IMongoCollection<TDocument> does not derive from IMongoCollection we have to list IMongoCollection here as an interface we implement.

@@ -23,6 +23,13 @@

namespace MongoDB.Driver
{
internal interface IMongoCollection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it is. Could you please add this to the TODO list for next major release? https://docs.google.com/document/d/1pGrELOhAvzXvavUDqIA-su0ic6wf2Mu6h20llrYj_VA

Ensure.IsNotNull(localField, nameof(localField));
Ensure.IsNotNull(foreignField, nameof(foreignField));

return source.Provider.CreateQuery<LookupResult<TSource, TForeign>>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be source.GetMongoQueryProvider() instead to validate the provider is IMongoQueryProvider?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants