private IEnumerable <BsonDocument> GetAllList(TransactionService transaction, Snapshot snapshot) { // get empty page list, from header foreach (var page in this.GetList(_header.FreeEmptyPageList, null, transaction, snapshot)) { yield return(page); } // get lists from data pages/index list foreach (var collection in _collections) { var snap = transaction.CreateSnapshot(LockMode.Read, collection.Value, false); for (var slot = 0; slot < PAGE_FREE_LIST_SLOTS; slot++) { var result = this.GetList(snap.CollectionPage.FreeDataPageList[slot], null, transaction, snap); foreach (var page in result) { yield return(page); } } var indexes = snap.CollectionPage.GetCollectionIndexes().ToArray(); foreach (var index in indexes) { var result = this.GetList(index.FreeIndexPageList, index.Name, transaction, snap); foreach (var page in result) { yield return(page); } } } }
/// <summary> /// INCLUDE: Do include in result document according path expression - Works only with DocumentLookup /// </summary> protected async IAsyncEnumerable <BsonDocument> Include(IAsyncEnumerable <BsonDocument> source, BsonExpression path) { // cached services string last = null; Snapshot snapshot = null; IndexService indexer = null; DataService data = null; CollectionIndex index = null; IDocumentLookup lookup = null; await foreach (var doc in source) { foreach (var value in path.Execute(doc, _pragmas.Collation) .Where(x => x.IsDocument || x.IsArray) .ToList()) { // if value is document, convert this ref document into full document (do another query) if (value.IsDocument) { await DoInclude(value.AsDocument); } else { // if value is array, do same per item foreach (var item in value.AsArray .Where(x => x.IsDocument) .Select(x => x.AsDocument)) { await DoInclude(item); } } } yield return(doc); } async Task DoInclude(BsonDocument value) { // works only if is a document var refId = value["$id"]; var refCol = value["$ref"]; // if has no reference, just go out if (refId.IsNull || !refCol.IsString) { return; } // do some cache re-using when is same $ref (almost always is the same $ref collection) if (last != refCol.AsString) { last = refCol.AsString; // initialize services snapshot = await _transaction.CreateSnapshot(LockMode.Read, last, false); indexer = new IndexService(snapshot, _pragmas.Collation); data = new DataService(snapshot); lookup = new DatafileLookup(data, _pragmas.UtcDate, null); index = snapshot.CollectionPage?.PK; } // fill only if index and ref node exists if (index != null) { var node = await indexer.Find(index, refId, false, Query.Ascending); if (node != null) { // load document based on dataBlock position var refDoc = await lookup.Load(node); //do not remove $id value.Remove("$ref"); // copy values from refDocument into current documet (except _id - will keep $id) foreach (var element in refDoc.Where(x => x.Key != "_id")) { value[element.Key] = element.Value; } } else { // set in ref document that was not found value["$missing"] = true; } } } }
/// <summary> /// INCLUDE: Do include in result document according path expression - Works only with DocumentLookup /// </summary> protected IEnumerable <BsonDocument> Include(IEnumerable <BsonDocument> source, BsonExpression path) { // cached services string last = null; Snapshot snapshot = null; IndexService indexer = null; DataService data = null; CollectionIndex index = null; IDocumentLookup lookup = null; foreach (var doc in source) { foreach (var value in path.Execute(doc) .Where(x => x.IsDocument) .Select(x => x.AsDocument) .ToList()) { // works only if is a document var refId = value["$id"]; var refCol = value["$ref"]; // if has no reference, just go out if (refId.IsNull || !refCol.IsString) { continue; } // do some cache re-using when is same $ref (almost always is the same $ref collection) if (last != refCol.AsString) { last = refCol.AsString; // initialize services snapshot = _transaction.CreateSnapshot(LockMode.Read, last, false); indexer = new IndexService(snapshot); data = new DataService(snapshot); lookup = new DatafileLookup(data, _utcDate, null); index = snapshot.CollectionPage?.PK; } // fill only if index and ref node exists if (index != null) { var node = indexer.Find(index, refId, false, Query.Ascending); if (node != null) { // load document based on dataBlock position var refDoc = lookup.Load(node); value.Remove("$id"); value.Remove("$ref"); refDoc.CopyTo(value); } } } yield return(doc); } }