diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5185b48..35f3527 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,22 +10,31 @@ "installMaven": "true", "mavenVersion": "3.9.10" }, - "ghcr.io/devcontainers/features/python:1": {} + // https: //github.com/devcontainers/features/tree/main/src/python + "ghcr.io/devcontainers/features/python:1": { + "version": "3.12" + }, + "ghcr.io/devcontainers/features/dotnet:2.3.0": { + "version": "9.0", + "installUsingApt": true + } }, "updateContentCommand": "bash .devcontainer/install-mongodb-db-tools.sh && bash .devcontainer/setup.sh && bash .devcontainer/import.sh", "postCreateCommand": "", "postAttachCommand": "", - "postStartCommand": "jupyter trust java/*.ipynb && jupyter trust javascript/*.ipynb && jupyter trust python/*.ipynb && jupyter notebook .", + "postStartCommand": "jupyter trust java/*.ipynb && jupyter trust javascript/*.ipynb && jupyter trust python/*.ipynb && jupyter trust dotnet/*.ipynb && jupyter notebook dotnet/*.ipynb", "customizations": { "codespaces": { "openFiles": [ - "README.md" + "dotnet/00_open_mongodb.ipynb" ] }, "vscode": { "extensions": [ "ms-toolsai.jupyter", - "mongodb.mongodb-vscode" + "mongodb.mongodb-vscode", + "ms-dotnettools.csharp", + "ms-dotnettools.dotnet-interactive-vscode" ] } }, diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index f1d2943..a894557 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -24,6 +24,10 @@ echo ✅ ----------------------------- sudo apt-get install python3-pymongo -y sudo apt-get clean packages +# Dotnet Kernel +sudo dotnet tool install -g Microsoft.dotnet-interactive +sudo dotnet interactive jupyter install + echo ✅ Install Deno echo ✅ ------------ # Install deno - Nodejs modern engine diff --git a/dotnet/00_open_mongodb.ipynb b/dotnet/00_open_mongodb.ipynb new file mode 100644 index 0000000..131d672 --- /dev/null +++ b/dotnet/00_open_mongodb.ipynb @@ -0,0 +1,58 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Open MongoDB Using the MongoDB Extension\n", + "\n", + "- click on the MongoDB extension on the side panel\n", + "- add a new connection clicking on `Add Connection`\n", + "- use as connection:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + "mongodb://admin:mongodb@localhost:27017/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You should see four databases in the MongoDB database server:\n", + "- admin\n", + "- config\n", + "- local\n", + "- library -> we're going to work with this one" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Open the library database\n", + "\n", + "- open the library database\n", + "- open the books collection\n", + "- click on Documents\n", + "- open a document" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/dotnet/01_connect_database.ipynb b/dotnet/01_connect_database.ipynb new file mode 100644 index 0000000..4bd7184 --- /dev/null +++ b/dotnet/01_connect_database.ipynb @@ -0,0 +1,114 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "409549ea", + "metadata": {}, + "source": [ + "# Install the MongoDB Driver" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3de619e", + "metadata": { + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;" + ] + }, + { + "cell_type": "markdown", + "id": "22d7c5ea", + "metadata": {}, + "source": [ + "# Create new client and run a basic command to test connection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53fb64de", + "metadata": { + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"MongoDB server version: \" + result.ToJson());\n" + ] + }, + { + "cell_type": "markdown", + "id": "03c03c08", + "metadata": {}, + "source": [ + "# List all databases and collections in the cluster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var dbs = client.ListDatabaseNames().ToList();\n", + "\n", + "foreach(var db in dbs)\n", + "{\n", + " Console.WriteLine(db);\n", + " var database = client.GetDatabase(db); \n", + " var collectionNames = database.ListCollectionNames().ToList(); \n", + "\n", + " foreach (var collName in collectionNames) \n", + " { \n", + " Console.WriteLine($\" - {collName}\"); \n", + " } \n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/100_aggregation_pipeline_match.ipynb b/dotnet/100_aggregation_pipeline_match.ipynb new file mode 100644 index 0000000..58e4093 --- /dev/null +++ b/dotnet/100_aggregation_pipeline_match.ipynb @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2cb888cd", + "metadata": {}, + "source": [ + "# Aggregation Pipeline - $match and $project\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "8de7bad1", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91af4866", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\"); " + ] + }, + { + "cell_type": "markdown", + "id": "04592620", + "metadata": {}, + "source": [ + "## $match" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1cafd6d4", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "List booksFrom2010 = booksCollection.Aggregate()\n", + " .Match(b => b.Year == 2010).ToList();\n", + "\n", + "\n", + "if(booksFrom2010 != null)\n", + "{\n", + " foreach(var book in booksFrom2010)\n", + " {\n", + " Console.WriteLine($\"Title: {book.Title} - Year: {book.Year}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found from 2010\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "0fd53598", + "metadata": {}, + "source": [ + "### Exercise: get all books from 2010 and 2012" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83f267fd", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.And(\n", + " Builders.Filter.Eq(b => b.Year, 2010),\n", + " // Add code here\n", + ");\n", + "\n", + "List booksFrom2010And2012 = booksCollection.Aggregate().Match(filter).ToList();\n", + "\n", + "if(booksFrom2010And2012 != null)\n", + "{\n", + " foreach(var book in booksFrom2010And2012)\n", + " {\n", + " Console.WriteLine($\"Title: {book.Title} - Year: {book.Year}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found from 2010 and 2012\");\n", + "}\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "d5acd5ed", + "metadata": {}, + "source": [ + "## Exercise: get all books from 2010 or 2012" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7f38578", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.Or(\n", + " Builders.Filter.Eq(b => b.Year, 2010),\n", + " // Add code here\n", + ");\n", + "\n", + "List booksFrom2010Or2012 = booksCollection.Aggregate().Match(filter).ToList();\n", + "\n", + "if(booksFrom2010Or2012 != null)\n", + "{\n", + " foreach(var book in booksFrom2010Or2012)\n", + " {\n", + " Console.WriteLine($\"Title: {book.Title} - Year: {book.Year}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found from 2010 or 2012\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "4d4106e2", + "metadata": {}, + "source": [ + "## $project\n", + "Let's show only `_id`, `year` and `title` of our books!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "980526d0", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// _id is included by default so unlike other fields, you don't need to explicitly include it here.\n", + "var showTitleAndYear = Builders.Projection.Include(b => b.Title)\n", + ".Include(b => b.Year);\n", + "\n", + "List booksFrom2010 = booksCollection.Aggregate()\n", + " .Match(b => b.Year == 2010)\n", + " .Project(showTitleAndYear).ToList();\n", + "\n", + "if(booksFrom2010 != null)\n", + "{\n", + " foreach(var book in booksFrom2010)\n", + " {\n", + " Console.WriteLine($\"Id: {book.Id} Title: {book.Title} - Year: {book.Year}\");\n", + " }\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"No books found from 2010\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "db26cd85", + "metadata": {}, + "source": [ + "### Show all fields except `id`, `pages`, `totalInventory`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e83266a", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var matchStage = Builders.Filter.Eq(b => b.Year, 2010);\n", + "\n", + "var projection = Builders.Projection\n", + " .Exclude(b => b.Id)\n", + " .Exclude(b => b.Pages)\n", + " .Exclude(b => b.TotalInventory);\n", + "\n", + "var pipeline = booksCollection.Aggregate()\n", + " .Match(matchStage)\n", + " .Project(projection);\n", + "\n", + "List booksFrom2010Projected = pipeline.ToList();\n", + "\n", + "if(booksFrom2010Projected != null)\n", + "{\n", + " foreach(var book in booksFrom2010Projected)\n", + " {\n", + " Console.WriteLine(book.ToJson()); // Shows the entire BSON document as JSON to show that some fields are null because they are not returned due to the projection\n", + "\n", + " }\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"No books found from 2010\");\n", + "}\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/101_aggregation_pipeline_arrays.ipynb b/dotnet/101_aggregation_pipeline_arrays.ipynb new file mode 100644 index 0000000..9fe63c0 --- /dev/null +++ b/dotnet/101_aggregation_pipeline_arrays.ipynb @@ -0,0 +1,176 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a9216694", + "metadata": {}, + "source": [ + "# Aggregation Pipeline - How to query arrays\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "769c4375", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6abd046a", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "584f2e9c", + "metadata": {}, + "source": [ + "## $match: $all\n", + "\n", + "https://mongodb-developer.github.io/aggregation-pipeline-lab/docs/using-arrays/simple-match-array " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9871505d", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.All(b => b.Genres, new [] { \"Police\", \"Fiction\"});\n", + "\n", + "List filteredBooks = booksCollection.Find(filter).ToList();\n", + "\n", + "if(filteredBooks != null)\n", + "{\n", + " foreach(var book in filteredBooks)\n", + " {\n", + " Console.WriteLine($\"Title: {book.Title} - Genres: {string.Join(\", \", book.Genres)}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found\");\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "id": "a1a618ce", + "metadata": {}, + "source": [ + "## $match: $in" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.In(\"genres\", new [] { \"Police\", \"Fiction\"});\n", + "\n", + "List filteredBooks = booksCollection.Find(filter).ToList();\n", + "\n", + "if(filteredBooks != null)\n", + "{\n", + " foreach(var book in filteredBooks)\n", + " {\n", + " Console.WriteLine($\"Title: {book.Title} - Genres: {string.Join(\", \", book.Genres)}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/102_aggregation_pipeline_unwind.ipynb b/dotnet/102_aggregation_pipeline_unwind.ipynb new file mode 100644 index 0000000..5e9a77b --- /dev/null +++ b/dotnet/102_aggregation_pipeline_unwind.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5973752d", + "metadata": {}, + "source": [ + "# Aggregation Pipeline - $unwind\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "13a48dd4", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c35787da", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "\n", + " [BsonElement(\"attributes\")]\n", + " public IEnumerable Attributes { get; set; }\n", + "\n", + "}\n", + "\n", + "// Attributes is embedded documents so we can create a class to represent that\n", + "public class Attribute\n", + "{\n", + " [BsonElement(\"key\")]\n", + " public string Key { get; set; }\n", + "\n", + " [BsonElement(\"value\")]\n", + " public string Value { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "351b24d4", + "metadata": {}, + "source": [ + "## $unwind" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var bookFilter = Builders.Filter.Eq(b => b.Id, \"68f119572a033e4f4377ab3c\"); // Replace with an actual book ID from your collection\n", + "var unwoundAttributes = booksCollection.Aggregate().Match(bookFilter).Unwind(b => b.Attributes).ToList();\n", + "\n", + "if(unwoundAttributes != null)\n", + "{\n", + " foreach(var attribute in unwoundAttributes)\n", + " {\n", + " Console.WriteLine(attribute);\n", + " }\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"No attributes found or book does not exist.\");\n", + "}\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/103_aggregation_pipeline_lookup.ipynb b/dotnet/103_aggregation_pipeline_lookup.ipynb new file mode 100644 index 0000000..f013c51 --- /dev/null +++ b/dotnet/103_aggregation_pipeline_lookup.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "23093a63", + "metadata": {}, + "source": [ + "# Aggregation Pipeline - $lookup" + ] + }, + { + "cell_type": "markdown", + "id": "a74d30cb", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e5cf845", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Author\n", + "{\n", + " [BsonElement(\"name\")]\n", + " public string Name { get; set; }\n", + "\n", + " [BsonElement(\"books\")]\n", + " public IEnumerable Books { get; set; }\n", + "\n", + " [BsonElement(\"aliases\")]\n", + " public IEnumerable Aliases { get; set; }\n", + "\n", + " [BsonElement(\"booksWritten\")]\n", + " public IEnumerable BooksWritten { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");\n", + "IMongoCollection authorsCollection = db.GetCollection(\"authors\");" + ] + }, + { + "cell_type": "markdown", + "id": "7763c1b4", + "metadata": {}, + "source": [ + "## $lookup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9e93c9a", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "List lookedUpBooks = authorsCollection.Aggregate()\n", + " .Lookup(\n", + " foreignCollection: booksCollection,\n", + " localField: a => a.Books,\n", + " foreignField: b => b.Id,\n", + " @as: a => a.BooksWritten)\n", + " .Limit(10)\n", + " .ToList();\n", + "\n", + " foreach (var author in lookedUpBooks)\n", + "{\n", + " if (author.BooksWritten != null)\n", + " {\n", + " foreach (var book in author.BooksWritten)\n", + " {\n", + " Console.WriteLine($\"Author: {author.Name} Title: {book.Title}\");\n", + " }\n", + " }\n", + " else\n", + " {\n", + " Console.WriteLine($\"Author: {author.Name} has no books\");\n", + " }\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/104_aggregation_pipeline_group_by.ipynb b/dotnet/104_aggregation_pipeline_group_by.ipynb new file mode 100644 index 0000000..4326db9 --- /dev/null +++ b/dotnet/104_aggregation_pipeline_group_by.ipynb @@ -0,0 +1,188 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cb760021", + "metadata": {}, + "source": [ + "# Aggregation Pipeline - $group by" + ] + }, + { + "cell_type": "markdown", + "id": "96bbcaa4", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57dd5a4d", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "\n", + " [BsonElement(\"totalBooks\")]\n", + " public int? TotalBooks { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "e2a82ebf", + "metadata": {}, + "source": [ + "## $group by" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3efc92e6", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var pipeline = new EmptyPipelineDefinition()\n", + " .Group(\n", + " id: b => b.Year,\n", + " group: g => new\n", + " {\n", + " Year = g.Key,\n", + " TotalBooks = g.Count()\n", + " }\n", + " )\n", + " .Limit(50); // Limit to 50 results for demo purposes otherwise it would return all years and take a very long time!\n", + "\n", + "var groupedBooks = booksCollection.Aggregate(pipeline).ToList();\n", + "\n", + "if(groupedBooks != null)\n", + "{ \n", + " foreach (var yearGroup in groupedBooks)\n", + " {\n", + " Console.WriteLine($\"Year: {yearGroup.Year} - Total Books: {yearGroup.TotalBooks}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found.\");\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5145953", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var pipeline = new EmptyPipelineDefinition()\n", + " .Group(\n", + " id: b => b.Year,\n", + " group: g => new\n", + " {\n", + " Year = g.Key,\n", + " TotalBooks = g.Count(),\n", + " TotalPagesPublished = g.Sum(b => b.Pages),\n", + " AvgPagesPublished = g.Average(b => b.Pages)\n", + " }\n", + " );\n", + "\n", + "var groupedAndAverageBooks = booksCollection.Aggregate(pipeline).ToList();\n", + "\n", + "if(groupedAndAverageBooks != null)\n", + "{\n", + " foreach (var yearGroup in groupedAndAverageBooks)\n", + " {\n", + " Console.WriteLine($\"Year: {yearGroup.Year} - Total Pages: {yearGroup.TotalPagesPublished} - Avg Pages: {Math.Round(yearGroup.AvgPagesPublished ?? 0, 0)}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found.\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/10_find.ipynb b/dotnet/10_find.ipynb new file mode 100644 index 0000000..74136f2 --- /dev/null +++ b/dotnet/10_find.ipynb @@ -0,0 +1,415 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6c6e4eb4", + "metadata": {}, + "source": [ + "# CRUD: Find" + ] + }, + { + "cell_type": "markdown", + "id": "4a2ecdb0", + "metadata": {}, + "source": [ + "## Add the MongoDB Driver, using statements and connection string" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea160409", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";" + ] + }, + { + "cell_type": "markdown", + "id": "49347446", + "metadata": {}, + "source": [ + "## Setup and test connection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a5b1f40", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "// Test connection as best practice\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");" + ] + }, + { + "cell_type": "markdown", + "id": "aeec7c98", + "metadata": {}, + "source": [ + "## Create Book class to represent the document as a model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c1b8eca", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// This tells the driver to ignore any extra fields in documents that don't have properties so we can focus on the fields that matter\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " // Mark this property as the _id field so we can use the standard string data type and the driver will handle converting to/from ObjectId\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " // Add attribute to handle naming conventions between MongoDB and C# properties.\n", + " // You can also achieve this with CamelCaseConventions if you wish \n", + " // https://www.mongodb.com/docs/drivers/csharp/current/serialization/#conventions\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public List Genres { get; set; }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "a9c3e9b1", + "metadata": {}, + "source": [ + "## Setup database and collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed7e16dd", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "a33527c5", + "metadata": {}, + "source": [ + "## Find one book\n", + "\n", + "This is the R part in CRUD. We use `find()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0207f388", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "Book aBook = booksCollection.Find(b => true).FirstOrDefault();\n", + "\n", + "if(aBook != null)\n", + "{\n", + " Console.WriteLine($\"Book Title: {aBook.Title} - Year: {aBook.Year}\");\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "3cd9575b", + "metadata": {}, + "source": [ + "## Find 10 books written after 2014" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b139deb0", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var booksAfter2014Filter = Builders.Filter.Gt(b => b.Year, 2014);\n", + "\n", + "// You could remove .Limit(10) to find all books. This is added for readability of results.\n", + "List booksAfter2014 = booksCollection.Find(booksAfter2014Filter).Limit(10).ToList();\n", + "\n", + "if(booksAfter2014 != null)\n", + "{\n", + " foreach(var book in booksAfter2014)\n", + " {\n", + " Console.WriteLine($\"Book Title: {book.Title} - Year: {book.Year}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "id": "d5f79f2b", + "metadata": {}, + "source": [ + "## Find all the books that have fewer than 50 pages and project only the title and pages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b298237e", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var booksWithFewerThan50Pages = Builders.Filter.Lt(b => b.Pages, 50);\n", + "var showOnlyTitleAndPages = Builders.Projection\n", + ".Include(b => b.Title).Include(b => b.Pages);\n", + "\n", + "List filteredBooks = booksCollection.Find(booksWithFewerThan50Pages)\n", + ".Project(showOnlyTitleAndPages).ToList();\n", + "\n", + "if(filteredBooks != null)\n", + "{\n", + " foreach(var book in filteredBooks)\n", + " {\n", + " Console.WriteLine($\"Book Title: {book.Title} - Pages: {book.Pages}\");\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "47bd420f", + "metadata": {}, + "source": [ + "### Exclude _id field and limit to 10 results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94ce0ff6", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var booksWithFewerThan50Pages = Builders.Filter.Lt(b => b.Pages, 50);\n", + "var showOnlyTitleAndPages = Builders.Projection\n", + ".Include(b => b.Title).Include(b => b.Pages)\n", + ".Exclude(b => b.Id);\n", + "\n", + "List filteredBooks = booksCollection.Find(booksWithFewerThan50Pages)\n", + ".Limit(10)\n", + ".Project(showOnlyTitleAndPages).ToList();\n", + "\n", + "if(filteredBooks != null)\n", + "{\n", + " foreach(var book in filteredBooks)\n", + " {\n", + " Console.WriteLine($\"Book Title: {book.Title} - Pages: {book.Pages}\");\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "b6016922", + "metadata": {}, + "source": [ + "# Challenges" + ] + }, + { + "cell_type": "markdown", + "id": "5aadbe22", + "metadata": {}, + "source": [ + "### Find all books wherfe totalInventory is exactly 5\n", + "\n", + "[Solution Here](https://mongodb-developer.github.io/sql-to-query-api-lab/docs/CRUD/WHERE#1-find-all-books-where-totalinventory-is-exactly-5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "173b03f7", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// type in your code here, you'll need to adapt the code a bit\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "e50475d7", + "metadata": {}, + "source": [ + "### Find all books with more than 300 pages\n", + "\n", + "[Solution here](https://mongodb-developer.github.io/sql-to-query-api-lab/docs/CRUD/WHERE#2-find-all-books-with-more-than-300-pages)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89f55b25", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// type in your code here, you'll need to adapt the code a bit" + ] + }, + { + "cell_type": "markdown", + "id": "a9eebc04", + "metadata": {}, + "source": [ + "### Find books in the Science genre that are more than 300 pages long\n", + "\n", + "[Solution here](https://mongodb-developer.github.io/sql-to-query-api-lab/docs/CRUD/WHERE#3-find-books-in-the-science-genre-that-are-more-than-300-pages-long)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c796863", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// type in your code here, you'll need to adapt the code a bit" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/11_find_arrays.ipynb b/dotnet/11_find_arrays.ipynb new file mode 100644 index 0000000..5324bf7 --- /dev/null +++ b/dotnet/11_find_arrays.ipynb @@ -0,0 +1,259 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "631fc5e7", + "metadata": {}, + "source": [ + "# CRUD: Find in arrays" + ] + }, + { + "cell_type": "markdown", + "id": "bee4c26e", + "metadata": {}, + "source": [ + "# Setup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a1c3b15", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "// Test connection as best practice\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " \n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "d183adf4", + "metadata": {}, + "source": [ + "## Find all books containing one genre" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.AnyEq(b => b.Genres, \"Romance\");\n", + "\n", + "List booksWithRomanceGenre = booksCollection.Find(filter).ToList();\n", + "\n", + "if(booksWithRomanceGenre != null)\n", + "{\n", + " foreach (var book in booksWithRomanceGenre)\n", + " {\n", + " var genres = string.Join(\", \", book.Genres); // flatten list into readable string\n", + " Console.WriteLine($\"Title: {book.Title} - Genres: {genres}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "id": "68d10fe1", + "metadata": {}, + "source": [ + "## Find all books containing all genres (AND)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.All(b => b.Genres, new[] { \"Family Life\", \"Fiction\" });\n", + "\n", + "List booksWithMultipleGenres = booksCollection.Find(filter).ToList();\n", + "\n", + "if(booksWithMultipleGenres != null)\n", + "{\n", + " foreach (var book in booksWithMultipleGenres)\n", + " {\n", + " var genres = string.Join(\", \", book.Genres); // flatten list into readable string\n", + " Console.WriteLine($\"Title: {book.Title} - Genres: {genres}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "b613ec92", + "metadata": {}, + "source": [ + "## Find all books containing one genre (OR)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// This is different to previous filter operators, it takes the string value of the array field rather than a lambda expression to access the property on a Book object\n", + "var filter = Builders.Filter.In(\"genres\", new [] { \"Tea\", \"Romance\"});\n", + "\n", + "List booksWithOneOfGenres = booksCollection.Find(filter).ToList();\n", + "\n", + "if(booksWithOneOfGenres != null)\n", + "{\n", + " foreach (var book in booksWithOneOfGenres)\n", + " {\n", + " var genres = string.Join(\", \", book.Genres); // flatten list into readable string\n", + " Console.WriteLine($\"Title: {book.Title} - Genres: {genres}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "0c259be4", + "metadata": {}, + "source": [ + "## Don't make this mistake!\n", + "\n", + "The query below will try to find books that have exactly two genres (Poetry and Fiction) in the designated order. The query looks for an exact match of the array. Usually we want to search inside the array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var filter = Builders.Filter.Eq(\"genres\", new[] { \"Poetry\", \"Fiction\" });\n", + "\n", + "List booksWithThoseExactGenresInThatExactOrder = booksCollection.Find(filter).ToList();\n", + "\n", + "if(booksWithThoseExactGenresInThatExactOrder != null)\n", + "{\n", + " foreach (var book in booksWithThoseExactGenresInThatExactOrder)\n", + " {\n", + " var genres = string.Join(\", \", book.Genres); // flatten list into readable string\n", + " Console.WriteLine($\"Title: {book.Title} - Genres: {genres}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/200_full_text_search_create_index.ipynb b/dotnet/200_full_text_search_create_index.ipynb new file mode 100644 index 0000000..b001150 --- /dev/null +++ b/dotnet/200_full_text_search_create_index.ipynb @@ -0,0 +1,184 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c154583a", + "metadata": {}, + "source": [ + "# Full Text Search - Create Index" + ] + }, + { + "cell_type": "markdown", + "id": "08bceb96", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cda98a83", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "f1cdccfc", + "metadata": {}, + "source": [ + "## Create Atlas Search index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddca796e", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var indexDefinition = new BsonDocument\n", + "{\n", + " { \"mappings\", new BsonDocument\n", + " {\n", + " { \"dynamic\", true },\n", + " { \"fields\", new BsonDocument\n", + " {\n", + " // This specifies the field(s) in the documents to index\n", + " { \"title\", new BsonDocument\n", + " {\n", + " { \"type\", \"autocomplete\" },\n", + " { \"analyzer\", \"lucene.standard\" }\n", + " }\n", + " }\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "try {\n", + " booksCollection.SearchIndexes.DropOne(\"default\");\n", + " Console.WriteLine(\"Full Text Search index dropped\");\n", + "} catch(MongoDB.Driver.MongoException ex)\n", + "{\n", + " Console.WriteLine($\"Error deleting index: {ex.Message}\");\n", + "}\n", + "\n", + "var indexModel = new CreateSearchIndexModel(\n", + " name: \"default\",\n", + " type: SearchIndexType.Search,\n", + " definition: indexDefinition\n", + ");\n", + "\n", + "// Create the index\n", + "var indexCreationResult = await booksCollection.SearchIndexes.CreateOneAsync(indexModel);\n", + "\n", + "Console.WriteLine($\"✅ Created Atlas Search index: {indexCreationResult}\");" + ] + }, + { + "cell_type": "markdown", + "id": "3e801966", + "metadata": {}, + "source": [ + "## Check that the index has been created" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0f57cc7", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "\n", + "var searchIndexes = booksCollection.SearchIndexes.List().ToList();\n", + "\n", + "foreach(var index in searchIndexes)\n", + "{\n", + " Console.WriteLine($\"Indexes: {index}\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/20_project_sort_limit.ipynb b/dotnet/20_project_sort_limit.ipynb new file mode 100644 index 0000000..1f2ef86 --- /dev/null +++ b/dotnet/20_project_sort_limit.ipynb @@ -0,0 +1,228 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c1359c36", + "metadata": {}, + "source": [ + "# CRUD: Project, Sort, Limit & Skip" + ] + }, + { + "cell_type": "markdown", + "id": "8bb768b5", + "metadata": {}, + "source": [ + "# Setup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd0b5ee4", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "// Test connection as best practice\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "dbbfa0f5", + "metadata": {}, + "source": [ + "## Sort books by descending number of pages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8d2a955", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var projection = Builders.Projection.Include(b => b.Title).Include(b => b.Pages);\n", + "var descendingPagesSort = Builders.Sort.Descending(\"pages\");\n", + "\n", + "List sortedBooks = booksCollection.Find(b => true) // Empty filter to find all books\n", + ".Project(projection)\n", + ".Limit(50)\n", + ".Sort(descendingPagesSort).ToList();\n", + "\n", + "if(sortedBooks != null)\n", + "{\n", + " foreach(var book in sortedBooks)\n", + " {\n", + " Console.WriteLine($\"Book Title: {book.Title} - Pages: {book.Pages}\");\n", + " }\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "4b24dec4", + "metadata": {}, + "source": [ + "## Limit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f61f5590", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var projection = Builders.Projection.Include(b => b.Title).Include(b => b.Pages);\n", + "var descendingPagesSort = Builders.Sort.Descending(\"pages\");\n", + "\n", + "List sortedBooksLimitedToTen = booksCollection.Find(b => true) // Empty filter to find all books\n", + ".Project(projection)\n", + ".Sort(descendingPagesSort)\n", + ".Limit(10).ToList();\n", + "\n", + "if(sortedBooksLimitedToTen != null)\n", + "{\n", + " foreach(var book in sortedBooksLimitedToTen)\n", + " {\n", + " Console.WriteLine($\"Book Title: {book.Title} - Pages: {book.Pages}\");\n", + " }\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "294b93e2", + "metadata": {}, + "source": [ + "## Skip" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f9903d7", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var projection = Builders.Projection.Include(b => b.Title).Include(b => b.Pages);\n", + "var descendingPagesSort = Builders.Sort.Descending(\"pages\");\n", + "\n", + "List sortedBooksLimitedToTenSkipFour = booksCollection.Find(b => true) // Empty filter to find all books\n", + ".Project(projection)\n", + ".Sort(descendingPagesSort)\n", + ".Skip(4)\n", + ".Limit(10).ToList();\n", + "\n", + "if(sortedBooksLimitedToTenSkipFour != null)\n", + "{\n", + " foreach(var book in sortedBooksLimitedToTenSkipFour)\n", + " {\n", + " Console.WriteLine($\"Book Title: {book.Title} - Pages: {book.Pages}\");\n", + " }\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"Empty Collection\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/210_full_text_search.ipynb b/dotnet/210_full_text_search.ipynb new file mode 100644 index 0000000..8ed29f1 --- /dev/null +++ b/dotnet/210_full_text_search.ipynb @@ -0,0 +1,200 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "785ae2e2", + "metadata": {}, + "source": [ + "## Full Text Search" + ] + }, + { + "cell_type": "markdown", + "id": "e2cc34eb", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3682be94", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "6e7802b4", + "metadata": {}, + "source": [ + "## $search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02f7d59", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// Define the $search stage\n", + "var searchStage = new BsonDocument(\"$search\", new BsonDocument\n", + "{\n", + " { \"index\", \"default\" },\n", + " { \"text\", new BsonDocument\n", + " {\n", + " { \"query\", \"Charity\" },\n", + " { \"path\", new BsonArray { \"title\", \"authors.name\", \"genres\" } }\n", + " }\n", + " }\n", + "});\n", + "\n", + "// Build the pipeline (you can add more stages if you like)\n", + "var pipeline = new[] { searchStage };\n", + "\n", + "// Execute aggregation\n", + "var results = await booksCollection.Aggregate(pipeline).ToListAsync();\n", + "\n", + "if(results != null)\n", + "{\n", + " foreach (var book in results)\n", + " {\n", + " Console.WriteLine($\"Title: {book.Title}\");\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found.\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "71b7182c", + "metadata": {}, + "source": [ + "## Fuzzy matching" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2caef5f", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var searchStage = new BsonDocument(\"$search\", new BsonDocument\n", + "{\n", + " { \"index\", \"default\" },\n", + " { \"text\", new BsonDocument\n", + " {\n", + " { \"query\", \"Charity\" },\n", + " { \"path\", new BsonArray { \"title\", \"authors.name\", \"genres\" } },\n", + " { \"fuzzy\", new BsonDocument\n", + " {\n", + " { \"maxEdits\", 2 }, // Up to 2 character differences\n", + " { \"prefixLength\", 1 }, // Number of exact chars before fuzziness starts\n", + " { \"maxExpansions\", 50 } // Optional, controls result breadth\n", + " }\n", + " }\n", + " }\n", + " }\n", + "});\n", + "\n", + "var pipeline = new[] { searchStage };\n", + "\n", + "var results = await booksCollection.Aggregate(pipeline).ToListAsync();\n", + "\n", + "if(results != null)\n", + "{\n", + " foreach (var doc in results)\n", + " {\n", + " Console.WriteLine(doc.ToJson(new MongoDB.Bson.IO.JsonWriterSettings { Indent = true }));\n", + " }\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"No books found.\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/30_insert.ipynb b/dotnet/30_insert.ipynb new file mode 100644 index 0000000..6f999c4 --- /dev/null +++ b/dotnet/30_insert.ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a7df87ef", + "metadata": {}, + "source": [ + "# CRUD: Insert" + ] + }, + { + "cell_type": "markdown", + "id": "714193dd", + "metadata": {}, + "source": [ + "## Setup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b996359d", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "9938e3c4", + "metadata": {}, + "source": [ + "## Insert one book" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7c204cd", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "Book elQuijote = new Book\n", + "{\n", + " Title = \"El Quijote\",\n", + " Year = 1500\n", + "};\n", + "\n", + "booksCollection.InsertOne(elQuijote);" + ] + }, + { + "cell_type": "markdown", + "id": "a7e8a545", + "metadata": {}, + "source": [ + "## Find the book we just inserted" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var elQuijoteFilter = Builders.Filter.Eq(b => b.Title, \"El Quijote\");\n", + "\n", + "Book newBook = booksCollection.Find(elQuijoteFilter).FirstOrDefault();\n", + "\n", + "if(newBook != null)\n", + "{\n", + " Console.WriteLine($\"Id: {newBook.Id} Title: {newBook.Title}, Year: {newBook.Year}\");\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"Book not found\");\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "e538cf09", + "metadata": {}, + "source": [ + "### Can you find the same document, but using the `_id` instead? Fix the code below!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var elQuijoteFilter = Builders.Filter.Eq(b => b.Id, \"\");\n", + "\n", + "var newBook = booksCollection.Find(elQuijoteFilter).FirstOrDefault();\n", + "\n", + "if(newBook != null)\n", + "{\n", + " Console.WriteLine($\"Id: {newBook.Id} Title: {newBook.Title}, Year: {newBook.Year}\");\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Book not found\");\n", + "}" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/40_delete.ipynb b/dotnet/40_delete.ipynb new file mode 100644 index 0000000..0da734d --- /dev/null +++ b/dotnet/40_delete.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ffb8d5e3", + "metadata": {}, + "source": [ + "# CRUD: Delete" + ] + }, + { + "cell_type": "markdown", + "id": "ff2a2667", + "metadata": {}, + "source": [ + "## Setup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d39a82b", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "9ec5bfe0", + "metadata": {}, + "source": [ + "## Insert one book\n", + "\n", + "We want to make sure this book is in the collection, so we can delete it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4584993c", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// We want to generate a unique _id we can use later to confirm we are deleting this book\n", + "var id = ObjectId.GenerateNewId().ToString();\n", + "\n", + "Book platero = new Book\n", + "{\n", + " Id = id,\n", + " Title = \"Platero y yo\",\n", + " Year = 1900\n", + "};\n", + "\n", + "booksCollection.InsertOne(platero);" + ] + }, + { + "cell_type": "markdown", + "id": "7d953849", + "metadata": {}, + "source": [ + "### Find the book using the `_id` field" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "868817ba", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var plateroFilter = Builders.Filter.Eq(b => b.Id, id);\n", + "\n", + "Book newBook = booksCollection.Find(plateroFilter).FirstOrDefault();\n", + "\n", + "if(newBook != null)\n", + "{\n", + " Console.WriteLine($\"Id: {newBook.Id} Title: {newBook.Title}, Year: {newBook.Year}\");\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Book not found\");\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "id": "25fecb94", + "metadata": {}, + "source": [ + "### Delete that book" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22aab1c0", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var deletionResult = booksCollection.DeleteOne(plateroFilter);\n", + "\n", + "Console.WriteLine(deletionResult);" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/50_update.ipynb b/dotnet/50_update.ipynb new file mode 100644 index 0000000..e0d8f59 --- /dev/null +++ b/dotnet/50_update.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4ce0e42b", + "metadata": {}, + "source": [ + "# CRUD: Update" + ] + }, + { + "cell_type": "markdown", + "id": "c8421ab8", + "metadata": {}, + "source": [ + "## Setup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09e9b802", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "6ff546fd", + "metadata": {}, + "source": [ + "## Update one book" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "436611c8", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// We want to generate a unique _id we can use later to confirm we are updating this specific book\n", + "var id = ObjectId.GenerateNewId().ToString();\n", + "\n", + "Book iliad = new Book\n", + "{\n", + " Id = id,\n", + " Title = \"Iliad\",\n", + " Year = 0 // Year is wrong\n", + "};\n", + "\n", + "booksCollection.InsertOne(iliad);\n", + "\n", + "// We also find and print that book\n", + "var iliadFilter = Builders.Filter.Eq(b => b.Id, id);\n", + "\n", + "Book newBook = booksCollection.Find(iliadFilter).FirstOrDefault();\n", + "\n", + "if(newBook != null)\n", + "{\n", + " Console.WriteLine($\"Before: Title: {newBook.Title}, Year: {newBook.Year}\");\n", + "}\n", + "\n", + "// We update this book's year\n", + "\n", + "var updateBookYearFilter = Builders.Update.Set(b => b.Year, -762);\n", + "\n", + "var updateResult = booksCollection.UpdateOne(iliadFilter, updateBookYearFilter);\n", + "\n", + "Console.WriteLine($\"Update Result: {updateResult}\");\n", + "\n", + "// We refetch the book with the updated year\n", + "var bookWithCorrectYear = booksCollection.Find(iliadFilter).FirstOrDefault();\n", + "\n", + "if(bookWithCorrectYear != null)\n", + "{\n", + " Console.WriteLine($\"After: Title: {bookWithCorrectYear.Title} Year: {bookWithCorrectYear.Year}\");\n", + "}\n", + "else\n", + "{\n", + " Console.WriteLine(\"Book not found after update\");\n", + "}\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "53769813", + "metadata": {}, + "source": [ + "## Upsert" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d41be3ed", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "// We make sure the book is not in the database!\n", + "// Note: If you want to run this cell multiple times, run the cell above to recreate the book\n", + "var deletionResult = booksCollection.DeleteOne(iliadFilter);\n", + "\n", + "Console.WriteLine($\"Deletion Result: {deletionResult}\");\n", + "\n", + "// This book does not exist!\n", + "\n", + "Book iliadBook = booksCollection.Find(iliadFilter).FirstOrDefault();\n", + "\n", + "if(iliadBook == null)\n", + "{\n", + " Console.WriteLine(\"Book not found\");\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(iliadBook.Title);\n", + "}\n", + "\n", + "// We \"upsert\" the book: update it if it's there, insert if not\n", + "var updateBookYearFilter = Builders.Update.Set(b => b.Title, \"Iliad\").Set(b => b.Year, -762);\n", + "\n", + "var upsertResult = booksCollection.UpdateOne(iliadFilter, updateBookYearFilter, new UpdateOptions { IsUpsert = true });\n", + "\n", + "// Look at the \"upserted\" field\n", + "Console.WriteLine($\"Upsert Result: {upsertResult}\");\n", + "\n", + "Book upsertedBook = booksCollection.Find(iliadFilter).FirstOrDefault();\n", + "\n", + "if(upsertedBook != null)\n", + "{\n", + " Console.WriteLine($\"After: Title: {upsertedBook.Title} Year: {upsertedBook.Year}\");\n", + "}\n", + "else \n", + "{\n", + " Console.WriteLine(\"Book not found\");\n", + "}\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dotnet/60_indexes.ipynb b/dotnet/60_indexes.ipynb new file mode 100644 index 0000000..3a01cb3 --- /dev/null +++ b/dotnet/60_indexes.ipynb @@ -0,0 +1,262 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ebf04b2b", + "metadata": {}, + "source": [ + "# Indexes" + ] + }, + { + "cell_type": "markdown", + "id": "abad9b7d", + "metadata": {}, + "source": [ + "## Startup Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d88f5d7", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "#r \"nuget:MongoDB.Driver\"\n", + "\n", + "using MongoDB.Driver;\n", + "using MongoDB.Bson;\n", + "using MongoDB.Bson.Serialization;\n", + "using MongoDB.Bson.Serialization.Attributes;\n", + "\n", + "string connectionString = \"mongodb://admin:mongodb@localhost:27017/\";\n", + "\n", + "MongoClient client = new MongoClient(connectionString);\n", + "\n", + "var result = client.GetDatabase(\"admin\").RunCommand(new BsonDocument(\"ping\", 1));\n", + "Console.WriteLine(\"Connected to MongoDB\");\n", + "\n", + "[BsonIgnoreExtraElements]\n", + "public class Book\n", + "{\n", + " [BsonRepresentation(BsonType.ObjectId)]\n", + " public string Id { get; set; }\n", + "\n", + " [BsonElement(\"title\")]\n", + " public string Title { get; set; }\n", + "\n", + " [BsonElement(\"year\")]\n", + " public int? Year { get; set; }\n", + "\n", + " [BsonElement(\"pages\")]\n", + " public int? Pages { get; set; }\n", + "\n", + " [BsonElement(\"totalInventory\")]\n", + " public int? TotalInventory { get; set; }\n", + "\n", + " [BsonElement(\"genres\")]\n", + " public IEnumerable Genres { get; set; }\n", + "}\n", + "\n", + "IMongoDatabase db = client.GetDatabase(\"library\");\n", + "IMongoCollection booksCollection = db.GetCollection(\"books\");" + ] + }, + { + "cell_type": "markdown", + "id": "8ac9ff0a", + "metadata": {}, + "source": [ + "## Drop the index if it exists" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e888bf22", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "try {\n", + " await booksCollection.Indexes.DropOneAsync(\"pages_1_year_1\");\n", + " Console.WriteLine(\"Index dropped\");\n", + "} catch(MongoDB.Driver.MongoException ex)\n", + "{\n", + " Console.WriteLine($\"Error deleting index: {ex.Message}\");\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "id": "68597eac", + "metadata": {}, + "source": [ + "## Query without the index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1aece8fd", + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "\n", + "\n", + "// We want to see how it performs without an index so so we are going to take advantage of the admin command 'explain'\n", + "\n", + "// Build the command, defined as a BSON document\n", + "var explainCmd = new BsonDocument\n", + "{\n", + " { \"explain\", new BsonDocument\n", + " {\n", + " { \"find\", \"books\" }, // collection name\n", + " { \"filter\", new BsonDocument\n", + " {\n", + " { \"pages\", 100 },\n", + " { \"year\", new BsonDocument(\"$gt\", 2008) }\n", + " }\n", + " }\n", + " }\n", + " },\n", + " { \"verbosity\", \"queryPlanner\" } // or \"queryPlanner\", \"allPlansExecution\"\n", + "};\n", + "\n", + "// Run the command\n", + "var explainDoc = await booksCollection.Database.RunCommandAsync(explainCmd);\n", + "\n", + "// Print nicely\n", + "Console.WriteLine(explainDoc.ToJson(new MongoDB.Bson.IO.JsonWriterSettings { Indent = true }));\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "a1a01e13", + "metadata": {}, + "source": [ + "## Create the index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var indexOptions = new CreateIndexOptions()\n", + "{\n", + " Name = \"pages_1_year_1\"\n", + "};\n", + "\n", + "CreateIndexModel pageAndYearIndex = new CreateIndexModel(Builders.IndexKeys.Ascending(b => b.Pages)\n", + ".Ascending(b => b.Year), indexOptions);\n", + "\n", + "\n", + "\n", + "booksCollection.Indexes.CreateOne(pageAndYearIndex);" + ] + }, + { + "cell_type": "markdown", + "id": "492e377d", + "metadata": {}, + "source": [ + "## Query with the index\n", + "\n", + "Check that the `stage` in the winning plan is `IXSCAN`. We're using the index!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelName": "csharp" + } + }, + "outputs": [], + "source": [ + "var explainCmd = new BsonDocument\n", + "{\n", + " { \"explain\", new BsonDocument\n", + " {\n", + " { \"find\", \"books\" }, // collection name\n", + " { \"filter\", new BsonDocument\n", + " {\n", + " { \"pages\", 100 },\n", + " { \"year\", new BsonDocument(\"$gt\", 2008) }\n", + " }\n", + " }\n", + " }\n", + " },\n", + " { \"verbosity\", \"queryPlanner\" } // or \"queryPlanner\", \"allPlansExecution\"\n", + "};\n", + "\n", + "// Run the command\n", + "var explainDoc = await booksCollection.Database.RunCommandAsync(explainCmd);\n", + "\n", + "// Print nicely\n", + "Console.WriteLine(explainDoc.ToJson(new MongoDB.Bson.IO.JsonWriterSettings { Indent = true }));\n", + "\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}