How to Run Atlas Search Queries Across Multiple Collections
This page contains tutorials that demonstrate the different ways you can run Atlas Search queries across multiple collections:
To join collections and search across them, use $lookup with $search.
To combine search results from multiple collections, $unionWith with $search.
To consolidate multiple collections so you can index and search them together, use materialized views.
Before you begin, ensure that your Atlas cluster meets the requirements described in the Prerequisites.
➤ Use the Select your language drop-down menu on this page to set the language of the examples on this page.
Search Joined Collections
Starting in v6.0, the MongoDB $lookup
aggregation stage
supports $search
inside the $lookup
pipeline
option. Using $lookup
, you can join
multiple collections in the same database at query-time and run a
$search
query to further narrow down your search.
This tutorial demonstrates how to run a $lookup
query
with $search
against the accounts
and customers
collections in the sample_analytics
database.
It takes you through the following steps:
Create a default Atlas Search index on the
accounts
collection in thesample_analytics
database.Run a
$lookup
query with$search
to find customers from thecustomers
collections whose accounts have purchased bothCurrencyService
andInvestmentStock
products in theaccounts
collection.
Considerations
To run $lookup
query with $search
, your
cluster must run MongoDB v6.0 or later. To upgrade your MongoDB version,
see Upgrade Major MongoDB Version for a Cluster.
$lookup
queries are not very performant because Atlas Search
does a full document lookup on the database for each document in the
collection.
To learn more, see Reduce $lookup
Operations.
Create the Atlas Search Index
Create an Atlas Search index named lookup-with-search-tutorial
on all the
fields in the sample_analytics.accounts
collection.
In Atlas, go to the Clusters page for your project.
Warning
Navigation Improvements In Progress
We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.
If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.
If it's not already displayed, select your desired project from the Projects menu in the navigation bar.
If it's not already displayed, click Clusters in the sidebar.
The Clusters page displays.
Start your index configuration.
Make the following selections on the page and then click Next.
Search Type | Select the Atlas Search index type. |
Index Name and Data Source | Specify the following information:
|
Configuration Method | For a guided experience, select Visual Editor. To edit the raw index definition, select JSON Editor. |
Note
Your Atlas Search index is named default
by default. If you keep this name, then your index will be the
default Search index for any Atlas Search query that does not specify a different index
option in
its operators. If you are creating multiple indexes, we recommend
that you maintain a consistent, descriptive naming convention across your indexes.
Specify an index definition.
The following index definition dynamically indexes the fields of supported types in the collection. You can use the Atlas Search Visual Editor or the Atlas Search JSON Editor in the Atlas user interface to create the index.
Review the default index definition for the collection.
Review the index definition.
Your index definition should look similar to the following:
{ "mappings": { "dynamic": true } } Click Next.
Run $lookup
with $search
to Search the Collections
➤ Use the Select your language drop-down menu on this page to set the language of the examples in this section.
Connect to your Atlas cluster and run the sample query against the
indexed collections in the sample_analytics
database.
Connect to your cluster in mongosh
.
Open mongosh
in a terminal window and connect to your
cluster. For detailed instructions on connecting, see
Connect via mongosh
.
Switch to the sample_analytics
database.
Run the following command at mongosh
prompt:
use sample_analytics
switched to db sample_analytics
Run the following $lookup
with Atlas Search $search
query.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
db.customers.aggregate([ { $lookup:{ "from": "accounts", "localField": "accounts", "foreignField": "account_id", "as": "purchases", "pipeline": [{ "$search": { "index": "lookup-with-search-tutorial", "compound": { "must": [{ "queryString": { "defaultPath": "products", "query": "products: (CurrencyService AND InvestmentStock)" } }], "should": [{ "range": { "path": "limit", "gte": 5000, "lte": 10000 } }] } } },{ "$project": { "_id": 0 } }] } },{ "$limit": 5 },{ "$project": { "_id": 0, "address": 0, "birthdate": 0, "username": 0, "tier_and_details": 0 } } ])
[ { name: 'Elizabeth Ray', email: 'arroyocolton@gmail.com', active: true, accounts: [ 371138, 324287, 276528, 332179, 422649, 387979 ], purchases: [ { account_id: 422649, limit: 10000, products: [ 'CurrencyService', 'InvestmentStock' ] }, { account_id: 324287, limit: 10000, products: [ 'Commodity', 'CurrencyService', 'Derivatives', 'InvestmentStock' ] }, { account_id: 332179, limit: 10000, products: [ 'Commodity', 'CurrencyService', 'InvestmentFund', 'Brokerage', 'InvestmentStock' ] } ] }, { name: 'Lindsay Cowan', email: 'cooperalexis@hotmail.com', accounts: [ 116508 ], purchases: [] }, { name: 'Katherine David', email: 'timothy78@hotmail.com', accounts: [ 462501, 228290, 968786, 515844, 377292 ], purchases: [ { account_id: 228290, limit: 10000, products: [ 'CurrencyService', 'InvestmentStock', 'InvestmentFund', 'Brokerage' ] }, { account_id: 515844, limit: 10000, products: [ 'Commodity', 'CurrencyService', 'InvestmentFund', 'Brokerage', 'InvestmentStock' ] } ] }, { name: 'Leslie Martinez', email: 'tcrawford@gmail.com', accounts: [ 170945, 951849 ], purchases: [] }, { name: 'Brad Cardenas', email: 'dustin37@yahoo.com', accounts: [ 721914, 817222, 973067, 260799, 87389 ], purchases: [ { account_id: 87389, limit: 10000, products: [ 'CurrencyService', 'InvestmentStock' ] }, { account_id: 260799, limit: 10000, products: [ 'Brokerage', 'InvestmentStock', 'Commodity', 'CurrencyService' ] } ] } ]
Connect to your cluster in MongoDB Compass.
Open MongoDB Compass and connect to your cluster. For detailed instructions on connecting, see Connect via Compass.
Run an Atlas Search query against the collection.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
To run this query in MongoDB Compass:
Click the Aggregations tab.
Click Select..., then configure each of the following pipeline stages by selecting the stage from the dropdown and adding the query for that stage. Click Add Stage to add additional stages.
Pipeline StageQuery$lookup
{ from: "accounts", localField: "accounts", foreignField: "account_id", as: "purchases", pipeline: [ { $search: { index: "lookup-with-search-tutorial", compound: { must: [ { queryString: { defaultPath: "products", query: "products: (CurrencyService AND InvestmentStock)" } } ], should: [ { range: { path: "limit", gte: 5000, lte: 10000, } } ] } } }, { $project: { _id: 0, } } ] } $limit
5
$project
{ _id: 0, address: 0, birthdate: 0, username: 0, tier_and_details: 0, } If you enabled Auto Preview, MongoDB Compass displays the following documents next to the
$project
pipeline stage:name: Elizabeth Ray email: arroyocolton@gmail.com active: True accounts: Array (6) purchases: Array (3) name: "Lindsay Cowan" email: "cooperalexis@hotmail.com" accounts: Array (1) purchases: Array (empty) name: "Katherine David" email: "timothy78@hotmail.com" accounts: Array (5) urchases: Array (2) name: "Leslie Martinez" email: "tcrawford@gmail.com" accounts: Array (2) purchases: Array (empty) name: "Brad Cardenas" email: "dustin37@yahoo.com" accounts: Array (5) purchases: Array (2)
Set up and initialize the .NET/C# project for the query.
Create a new directory called
lookup-with-search
and initialize your project with the dotnet new command.mkdir lookup-with-search cd lookup-with-search dotnet new console Add the .NET/C# Driver to your project as a dependency.
dotnet add package MongoDB.Driver
Copy and paste the query into the Program.cs
file.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
1 using MongoDB.Bson; 2 using MongoDB.Bson.Serialization.Attributes; 3 using MongoDB.Bson.Serialization.Conventions; 4 using MongoDB.Driver; 5 using MongoDB.Driver.Core; 6 using MongoDB.Driver.Search; 7 8 public class LookupWithSearch{ 9 10 static void Main(string[] args) {// allow automapping of the camelCase database fields to our MovieDocument 11 var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; 12 ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true); 13 14 // connect to your Atlas cluster 15 var mongoClient = new MongoClient("<connection-string>"); 16 17 // define namespace 18 var analyticsDatabase = mongoClient.GetDatabase("sample_analytics"); 19 var accountsCollection = analyticsDatabase.GetCollection<AccountDocument>("accounts"); 20 var customersCollection = analyticsDatabase.GetCollection<CustomerDocument>("customers"); 21 22 // define pipeline stages 23 var lookupStage = new BsonDocument("$lookup", new BsonDocument{ 24 { "from", "accounts" }, { "localField", "accounts" }, { "foreignField", "account_id" }, 25 { "as", "purchases" }, { "pipeline", new BsonArray{ 26 new BsonDocument("$search", new BsonDocument{ 27 { "index", "lookup-with-search-tutorial" }, { "compound", new BsonDocument{ 28 { "must", new BsonArray{ 29 new BsonDocument("queryString", new BsonDocument{ 30 { "defaultPath", "products" }, { "query", "products: (CurrencyService AND InvestmentStock)" } 31 }) 32 }}, 33 { "should", new BsonArray{ 34 new BsonDocument("range", new BsonDocument{ 35 { "path", "limit" }, { "gte", 5000 }, { "lte", 10000 } 36 }) 37 }} 38 }} 39 }) 40 }} 41 }); 42 var projectStage1 = new BsonDocument("$project", new BsonDocument("_id", 0)); 43 var limitStage = new BsonDocument("$limit", 5); 44 var projectStage2 = new BsonDocument("$project", new BsonDocument{ 45 { "_id", 0 }, { "address", 0 }, { "birthdate", 0 }, { "username", 0 }, { "tier_and_details", 0 } 46 }); 47 var aggregationPipeline = new List<BsonDocument> {lookupStage, projectStage1, limitStage, projectStage2}; 48 49 // run pipeline 50 var results = customersCollection.Aggregate<BsonDocument>(aggregationPipeline).ToList(); 51 52 // print results 53 foreach (var acct in results) { 54 Console.WriteLine(acct.ToJson()); 55 } 56 } 57 } 58 59 // define fields in the accounts collection 60 [ ]61 public class AccountDocument { 62 [ ]63 [ ]64 [ ]65 public string Id { get; set; } 66 67 [ ]68 public int AccountId { get; set; } 69 70 [ ]71 public int Limit { get; set; } 72 } 73 74 // define fields in the customers collection 75 [ ]76 public class CustomerDocument { 77 [ ]78 [ ]79 [ ]80 public ObjectId Id { get; set; } 81 82 [ ]83 public string Name { get; set; } 84 85 [ ]86 public string Email { get; set; } 87 88 [ ]89 public bool Active { get; set; } 90 91 [ ]92 public List<int> Accounts { get; set; } 93 } 94 95 // define new array field for matching documents 96 public class CustomerLookedUp: CustomerDocument{ 97 public List<CustomerDocument> Purchases { get; set; } 98 }
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Compile and run the Program.cs
file.
dotnet run lookup-with-search.csproj
{ "name" : "Elizabeth Ray", "email" : "arroyocolton@gmail.com", "active" : true, "accounts" : [371138, 324287, 276528, 332179, 422649, 387979], "purchases" : [ { "_id" : ObjectId("5ca4bbc7a2dd94ee58162402"), "account_id" : 422649, "limit" : 10000, "products" : ["CurrencyService", "InvestmentStock"] }, { "_id" : ObjectId("5ca4bbc7a2dd94ee581623a9"), "account_id" : 324287, "limit" : 10000, "products" : ["Commodity", "CurrencyService", "Derivatives", "InvestmentStock"] }, { "_id" : ObjectId("5ca4bbc7a2dd94ee58162400"), "account_id" : 332179, "limit" : 10000, "products" : ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"] } ] } { "name" : "Lindsay Cowan", "email" : "cooperalexis@hotmail.com", "accounts" : [116508], "purchases" : [] } { "name" : "Katherine David", "email" : "timothy78@hotmail.com", "accounts" : [462501, 228290, 968786, 515844, 377292], "purchases" : [ { "_id" : ObjectId("5ca4bbc7a2dd94ee581623c9"), "account_id" : 228290, "limit" : 10000, "products" : ["CurrencyService", "InvestmentStock", "InvestmentFund", "Brokerage"] }, { "_id" : ObjectId("5ca4bbc7a2dd94ee581623cb"), "account_id" : 515844, "limit" : 10000, "products" : ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"] } ] } { "name" : "Leslie Martinez", "email" : "tcrawford@gmail.com", "accounts" : [170945, 951849], "purchases" : [] } { "name" : "Brad Cardenas", "email" : "dustin37@yahoo.com", "accounts" : [721914, 817222, 973067, 260799, 87389], "purchases" : [ { "_id" : ObjectId("5ca4bbc7a2dd94ee581623d6"), "account_id" : 87389, "limit" : 10000, "products" : ["CurrencyService", "InvestmentStock"] }, { "_id" : ObjectId("5ca4bbc7a2dd94ee581623d5"), "account_id" : 260799, "limit" : 10000, "products" : ["Brokerage", "InvestmentStock", "Commodity", "CurrencyService"] } ] }
Copy and paste the query into the lookup-with-search-query.go
file.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.mongodb.org/mongo-driver/v2/bson" 9 "go.mongodb.org/mongo-driver/v2/mongo" 10 "go.mongodb.org/mongo-driver/v2/mongo/options" 11 ) 12 13 func main() { 14 var err error 15 // connect to the Atlas cluster 16 ctx := context.Background() 17 clOpts := options.Client().ApplyURI("<connection-string>").SetTimeout(5 * time.Second) 18 client, err := mongo.Connect(clOpts) 19 if err != nil { 20 panic(err) 21 } 22 defer client.Disconnect(ctx) 23 // set namespace 24 collection := client.Database("sample_analytics").Collection("customers") 25 // define pipeline 26 lookupStage := bson.D{{Key: "$lookup", Value: bson.D{ 27 {Key: "from", Value: "accounts"}, 28 {Key: "localField", Value: "accounts"}, 29 {Key: "foreignField", Value: "account_id"}, 30 {Key: "as", Value: "purchases"}, 31 {Key: "pipeline", Value: bson.A{ 32 bson.D{ 33 {Key: "$search", Value: bson.D{ 34 {Key: "index", Value: "lookup-with-search-tutorial"}, 35 {Key: "compound", Value: bson.D{ 36 {Key: "must", Value: bson.A{ 37 bson.D{{Key: "queryString", Value: bson.D{ 38 {Key: "defaultPath", Value: "products"}, 39 {Key: "query", Value: "products: (CurrencyService AND InvestmentStock)"}, 40 }}}, 41 }}, 42 {Key: "should", Value: bson.A{ 43 bson.D{{Key: "range", Value: bson.D{ 44 {Key: "path", Value: "limit"}, 45 {Key: "gte", Value: 5000}, 46 {Key: "lte", Value: 10000}, 47 }}}, 48 }}, 49 }}, 50 }}, 51 }, 52 bson.D{{Key: "$project", Value: bson.D{ 53 {Key: "_id", Value: 0}, 54 {Key: "address", Value: 0}, 55 {Key: "birthdate", Value: 0}, 56 {Key: "username", Value: 0}, 57 {Key: "tier_and_details", Value: 0}, 58 }}}, 59 }}, 60 }}} 61 limitStage := bson.D{{Key: "$limit", Value: 5}} 62 projectStage := bson.D{{Key: "$project", Value: bson.D{ 63 {Key: "name", Value: 1}, 64 {Key: "email", Value: 1}, 65 {Key: "active", Value: 1}, 66 {Key: "accounts", Value: 1}, 67 {Key: "purchases", Value: 1}, 68 }}} 69 70 // run pipeline 71 cursor, err := collection.Aggregate(ctx, mongo.Pipeline{lookupStage, limitStage, projectStage}) 72 if err != nil { 73 panic(err) 74 } 75 // print results 76 var results []bson.D 77 if err = cursor.All(context.TODO(), &results); err != nil { 78 panic(err) 79 } 80 for _, result := range results { 81 fmt.Println(result) 82 } 83 }
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Run the command to query your collection.
go run lookup-with-search-query.go
{"_id":...,"name":"Gary Nichols","email":"laura34@yahoo.com","accounts":[{"$numberInt":"385397"},{"$numberInt":"337979"},{"$numberInt":"325377"},{"$numberInt":"440243"},{"$numberInt":"586395"},{"$numberInt":"86702"}],"purchases":[{"account_id":{"$numberInt":"337979"},"limit":{"$numberInt":"10000"},"products":["Brokerage","Derivatives","InvestmentStock","CurrencyService"]}]} {"_id":...,"name":"Ashley Lopez","email":"michael16@hotmail.com","accounts":[{"$numberInt":"662207"},{"$numberInt":"816481"}],"purchases":[]} {"_id":...,"name":"John Parks","email":"zmelton@gmail.com","accounts":[{"$numberInt":"702610"},{"$numberInt":"240640"}],"purchases":[{"account_id":{"$numberInt":"702610"},"limit":{"$numberInt":"10000"},"products":["Commodity","CurrencyService","InvestmentStock"]}]} {"_id":...,"name":"Jennifer Lawrence","email":"scott50@yahoo.com","accounts":[{"$numberInt":"344885"},{"$numberInt":"839927"},{"$numberInt":"853542"}],"purchases":[{"account_id":{"$numberInt":"853542"},"limit":{"$numberInt":"10000"},"products":["CurrencyService","InvestmentStock"]},{"account_id":{"$numberInt":"344885"},"limit":{"$numberInt":"10000"},"products":["Commodity","InvestmentFund","CurrencyService","InvestmentStock"]},{"account_id":{"$numberInt":"839927"},"limit":{"$numberInt":"10000"},"products":["InvestmentFund","CurrencyService","Brokerage","Commodity","InvestmentStock"]}]} {"_id":...,"name":"Jacqueline Haynes","email":"virginia36@hotmail.com","accounts":[{"$numberInt":"631901"},{"$numberInt":"814687"}],"purchases":[]}
Copy and paste the query into the LookupWithSearchQuery.java
file.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
1 import static com.mongodb.client.model.Aggregates.limit; 2 import static com.mongodb.client.model.Aggregates.project; 3 import static com.mongodb.client.model.Projections.*; 4 import java.util.Arrays; 5 import com.mongodb.client.MongoClient; 6 import com.mongodb.client.MongoClients; 7 import com.mongodb.client.MongoCollection; 8 import com.mongodb.client.MongoDatabase; 9 import org.bson.Document; 10 11 public class LookupWithSearchQuery { 12 13 public static void main(String[] args) { 14 // connect to your Atlas cluster 15 String uri = "<connection-string>"; 16 17 try (MongoClient mongoClient = MongoClients.create(uri)) { 18 // set namespace 19 MongoDatabase database = mongoClient.getDatabase("sample_analytics"); 20 MongoCollection<Document> collection = database.getCollection("customers"); 21 22 // define pipeline 23 Document agg = new Document("$lookup", 24 new Document("from", "accounts") 25 .append("localField", "accounts") 26 .append("foreignField", "account_id") 27 .append("as", "purchases") 28 .append("pipeline", Arrays.asList(new Document("$search", 29 new Document("index", "lookup-with-search-tutorial") 30 .append("compound", 31 new Document("must", Arrays.asList(new Document("queryString", 32 new Document("defaultPath", "products") 33 .append("query", "products: (CurrencyService AND InvestmentStock)")))) 34 .append("should", Arrays.asList(new Document("range", 35 new Document("path", "limit") 36 .append("gte", 5000L) 37 .append("lte", 10000L) 38 ))) 39 ) 40 ), 41 new Document("$limit", 5L), 42 new Document("$project", 43 new Document("_id", 0L) 44 .append("address", 0L) 45 .append("birthdate", 0L) 46 .append("username", 0L) 47 .append("tier_and_details", 0L) 48 ))) 49 ); 50 // run pipeline and print results 51 collection.aggregate(Arrays.asList(agg, 52 limit(5), 53 project(fields(excludeId(), include("name", "email", "active", "accounts", "purchases"))) 54 )) 55 .forEach(doc -> System.out.println(doc.toJson())); 56 } 57 } 58 }
Note
To run the sample code in your Maven environment, add the following code above the import statements in your file.
package com.mongodb.drivers;
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Compile and run the LookupWithSearchQuery.java
file.
javac LookupWithSearchQuery.java java LookupWithSearchQuery
{"name": "Elizabeth Ray", "email": "arroyocolton@gmail.com", "active": true, "accounts": [371138, 324287, 276528, 332179, 422649, 387979], "purchases": [{"account_id": 422649, "limit": 10000, "products": ["CurrencyService", "InvestmentStock"]}, {"account_id": 324287, "limit": 10000, "products": ["Commodity", "CurrencyService", "Derivatives", "InvestmentStock"]}, {"account_id": 332179, "limit": 10000, "products": ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"]}]} {"name": "Lindsay Cowan", "email": "cooperalexis@hotmail.com", "accounts": [116508], "purchases": []} {"name": "Katherine David", "email": "timothy78@hotmail.com", "accounts": [462501, 228290, 968786, 515844, 377292], "purchases": [{"account_id": 228290, "limit": 10000, "products": ["CurrencyService", "InvestmentStock", "InvestmentFund", "Brokerage"]}, {"account_id": 515844, "limit": 10000, "products": ["Commodity", "CurrencyService", "InvestmentFund", "Brokerage", "InvestmentStock"]}]} {"name": "Leslie Martinez", "email": "tcrawford@gmail.com", "accounts": [170945, 951849], "purchases": []} {"name": "Brad Cardenas", "email": "dustin37@yahoo.com", "accounts": [721914, 817222, 973067, 260799, 87389], "purchases": [{"account_id": 87389, "limit": 10000, "products": ["CurrencyService", "InvestmentStock"]}, {"account_id": 260799, "limit": 10000, "products": ["Brokerage", "InvestmentStock", "Commodity", "CurrencyService"]}]}
Copy and paste the query into the LookupWithSearchQuery.kt
file.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
1 import com.mongodb.client.model.Aggregates.limit 2 import com.mongodb.client.model.Aggregates.project 3 import com.mongodb.client.model.Projections.* 4 import com.mongodb.kotlin.client.coroutine.MongoClient 5 import kotlinx.coroutines.runBlocking 6 import org.bson.Document 7 import java.util.* 8 9 fun main() { 10 // connect to your Atlas cluster 11 val uri = "<connection-string>" 12 val mongoClient = MongoClient.create(uri) 13 14 // set namespace 15 val database = mongoClient.getDatabase("sample_analytics") 16 val collection = database.getCollection<Document>("customers") 17 18 runBlocking { 19 // define pipeline 20 val agg = Document( 21 "\$lookup", 22 Document("from", "accounts") 23 .append("localField", "accounts") 24 .append("foreignField", "account_id") 25 .append("as", "purchases") 26 .append( 27 "pipeline", Arrays.asList( 28 Document( 29 "\$search", 30 Document("index", "lookup-with-search-tutorial") 31 .append( 32 "compound", 33 Document( 34 "must", Arrays.asList( 35 Document( 36 "queryString", 37 Document("defaultPath", "products") 38 .append("query", "products: (CurrencyService AND InvestmentStock)") 39 ) 40 ) 41 ) 42 .append( 43 "should", Arrays.asList( 44 Document( 45 "range", 46 Document("path", "limit") 47 .append("gte", 5000) 48 .append("lte", 10000) 49 ) 50 ) 51 ) 52 ) 53 ), 54 Document("\$limit", 5), 55 Document( 56 "\$project", 57 Document("_id", 0) 58 .append("address", 0) 59 .append("birthdate", 0) 60 .append("username", 0) 61 .append("tier_and_details", 0) 62 ) 63 ) 64 ) 65 ) 66 67 // run pipeline and print results 68 val resultsFlow = collection.aggregate<Document>( 69 listOf( 70 agg, 71 limit(5), 72 project(fields(excludeId(), include("name", "email", "active", "accounts", "purchases"))) 73 ) 74 ) 75 resultsFlow.collect { println(it) } 76 } 77 mongoClient.close() 78 }
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Run the LookupWithSearchQuery.kt
file.
When you run the LookupWithSearchQuery.kt
program in your IDE, it prints
the following documents:
Document{{name=Elizabeth Ray, email=arroyocolton@gmail.com, active=true, accounts=[371138, 324287, 276528, 332179, 422649, 387979], purchases=[Document{{account_id=422649, limit=10000, products=[CurrencyService, InvestmentStock]}}, Document{{account_id=324287, limit=10000, products=[Commodity, CurrencyService, Derivatives, InvestmentStock]}}, Document{{account_id=332179, limit=10000, products=[Commodity, CurrencyService, InvestmentFund, Brokerage, InvestmentStock]}}]}} Document{{name=Lindsay Cowan, email=cooperalexis@hotmail.com, accounts=[116508], purchases=[]}} Document{{name=Katherine David, email=timothy78@hotmail.com, accounts=[462501, 228290, 968786, 515844, 377292], purchases=[Document{{account_id=228290, limit=10000, products=[CurrencyService, InvestmentStock, InvestmentFund, Brokerage]}}, Document{{account_id=515844, limit=10000, products=[Commodity, CurrencyService, InvestmentFund, Brokerage, InvestmentStock]}}]}} Document{{name=Leslie Martinez, email=tcrawford@gmail.com, accounts=[170945, 951849], purchases=[]}} Document{{name=Brad Cardenas, email=dustin37@yahoo.com, accounts=[721914, 817222, 973067, 260799, 87389], purchases=[Document{{account_id=87389, limit=10000, products=[CurrencyService, InvestmentStock]}}, Document{{account_id=260799, limit=10000, products=[Brokerage, InvestmentStock, Commodity, CurrencyService]}}]}}
Copy and paste the sample query into the lookup-with-search-query.js
file.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
1 const MongoClient = require("mongodb").MongoClient; 2 const assert = require("assert"); 3 4 const agg = [ 5 { 6 '$lookup': { 7 'from': 'accounts', 8 'localField': 'accounts', 9 'foreignField': 'account_id', 10 'as': 'purchases', 11 'pipeline': [ 12 { 13 '$search': { 14 'index': 'lookup-with-search-tutorial', 15 'compound': { 16 'must': [ 17 { 18 'queryString': { 19 'defaultPath': 'products', 20 'query': 'products: (CurrencyService AND InvestmentStock)' 21 } 22 } 23 ], 24 'should': [ 25 { 26 'range': { 27 'path': 'limit', 28 'gte': 5000, 29 'lte': 10000 30 } 31 } 32 ] 33 } 34 } 35 }, { 36 '$project': { 37 '_id': 0 38 } 39 } 40 ] 41 } 42 }, { 43 '$limit': 5 44 }, { 45 '$project': { 46 '_id': 0, 47 'address': 0, 48 'birthdate': 0, 49 'username': 0, 50 'tier_and_details': 0 51 } 52 } 53 ]; 54 55 MongoClient.connect( 56 "<connection-string>", 57 { useNewUrlParser: true, useUnifiedTopology: true }, 58 async function (connectErr, client) { 59 assert.equal(null, connectErr); 60 const coll = client.db("sample_analytics").collection("customers"); 61 let cursor = await coll.aggregate(agg); 62 await cursor.forEach((doc) => console.log(doc)); 63 client.close(); 64 } 65 );
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Query your collection.
Run the following command to query your collection:
node lookup-with-search-query.js
{ name: 'Elizabeth Ray', email: 'arroyocolton@gmail.com', active: true, accounts: [ 371138, 324287, 276528, 332179, 422649, 387979 ], purchases: [ { account_id: 422649, limit: 10000, products: [Array] }, { account_id: 324287, limit: 10000, products: [Array] }, { account_id: 332179, limit: 10000, products: [Array] } ] } { name: 'Lindsay Cowan', email: 'cooperalexis@hotmail.com', accounts: [ 116508 ], purchases: [] } { name: 'Katherine David', email: 'timothy78@hotmail.com', accounts: [ 462501, 228290, 968786, 515844, 377292 ], purchases: [ { account_id: 228290, limit: 10000, products: [Array] }, { account_id: 515844, limit: 10000, products: [Array] } ] } { name: 'Leslie Martinez', email: 'tcrawford@gmail.com', accounts: [ 170945, 951849 ], purchases: [] } { name: 'Brad Cardenas', email: 'dustin37@yahoo.com', accounts: [ 721914, 817222, 973067, 260799, 87389 ], purchases: [ { account_id: 87389, limit: 10000, products: [Array] }, { account_id: 260799, limit: 10000, products: [Array] } ] }
Copy and paste the query into the lookup-with-search-query.py
file.
The following query uses the following stages:
$lookup
to do the following:Join
customers
andaccounts
collections in thesample_analytics
database based on the account ID of the customers and return the matching documents from theaccounts
collection in an array field namedpurchases
.Use
$search
stage in the sub-pipeline to search for customer accounts thatmust
have purchased bothCurrencyService
andInvestmentStock
with preference for an order limit between5000
to10000
.
$limit
stage to limit the output to5
results.$project
stage to exclude the specified fields in the results.
1 import pymongo 2 3 # connect to your Atlas cluster 4 client = pymongo.MongoClient('<connection-string>') 5 6 # define pipeline 7 pipeline = [ 8 { 9 '$lookup': { 10 'from': 'accounts', 11 'localField': 'accounts', 12 'foreignField': 'account_id', 13 'as': 'purchases', 14 'pipeline': [ 15 { 16 '$search': { 17 'index': 'lookup-with-search-tutorial', 18 'compound': { 19 'must': [ 20 { 21 'queryString': { 22 'defaultPath': 'products', 23 'query': 'products: (CurrencyService AND InvestmentStock)' 24 } 25 } 26 ], 27 'should': [ 28 { 29 'range': { 30 'path': 'limit', 31 'gte': 5000, 32 'lte': 10000 33 } 34 } 35 ] 36 } 37 } 38 }, 39 { '$project': { '_id': 0 } } 40 ] 41 } 42 }, 43 { '$limit': 5 }, 44 { 45 '$project': { 46 '_id': 0, 47 'address': 0, 48 'birthdate': 0, 49 'username': 0, 50 'tier_and_details': 0 51 } 52 } 53 ] 54 55 # run pipeline 56 result = client['sample_analytics']['customers'].aggregate(pipeline) 57 58 # print results 59 for i in result: 60 print(i)
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Run the command to query your collection.
python lookup-with-search-query.py
{'name': 'Elizabeth Ray', 'email': 'arroyocolton@gmail.com', 'active': True, 'accounts': [371138, 324287, 276528, 332179, 422649, 387979], 'purchases': [{'account_id': 422649, 'limit': 10000, 'products': ['CurrencyService', 'InvestmentStock']}, {'account_id': 324287, 'limit': 10000, 'products': ['Commodity', 'CurrencyService', 'Derivatives', 'InvestmentStock']}, {'account_id': 332179, 'limit': 10000, 'products': ['Commodity', 'CurrencyService', 'InvestmentFund', 'Brokerage', 'InvestmentStock']}]} {'name': 'Lindsay Cowan', 'email': 'cooperalexis@hotmail.com', 'accounts': [116508], 'purchases': []} {'name': 'Katherine David', 'email': 'timothy78@hotmail.com', 'accounts': [462501, 228290, 968786, 515844, 377292], 'purchases': [{'account_id': 228290, 'limit': 10000, 'products': ['CurrencyService', 'InvestmentStock', 'InvestmentFund', 'Brokerage']}, {'account_id': 515844, 'limit': 10000, 'products': ['Commodity', 'CurrencyService', 'InvestmentFund', 'Brokerage', 'InvestmentStock']}]} {'name': 'Leslie Martinez', 'email': 'tcrawford@gmail.com', 'accounts': [170945, 951849], 'purchases': []} {'name': 'Brad Cardenas', 'email': 'dustin37@yahoo.com', 'accounts': [721914, 817222, 973067, 260799, 87389], 'purchases': [{'account_id': 87389, 'limit': 10000, 'products': ['CurrencyService', 'InvestmentStock']}, {'account_id': 260799, 'limit': 10000, 'products': ['Brokerage', 'InvestmentStock', 'Commodity', 'CurrencyService']}]}
Combine Query Results
Starting in v6.0, the MongoDB $unionWith
aggregation stage
supports $search
inside the $unionWith
pipeline
option. Using $unionWith
, you can combine
$search
results from multiple collections in the same
database in the result set.
This tutorial demonstrates how to run a $unionWith
query
with $search
against the companies
and inspections
collections in the sample_training
database. It takes you through
the following steps:
Create a default Atlas Search index on the
companies
andinspections
collections in thesample_training
database.Run a
$unionWith
query with$search
to perform a union of companies withmobile
in their name from both thecompanies
andinspections
collections.
Note
To run a $unionWith
query with $search
, your
cluster must run MongoDB v6.0 or higher. To upgrade your MongoDB version,
see Upgrade Major MongoDB Version for a Cluster.
Create the Atlas Search Indexes
In this section, you will create an Atlas Search index named default
on
all the fields in the companies
collection in the
sample_training
database. You will create another Atlas Search index
named default
on all the fields in the inspections
collection in the sample_training
database. You must perform the
following steps for each collection.
In Atlas, go to the Clusters page for your project.
Warning
Navigation Improvements In Progress
We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.
If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.
If it's not already displayed, select your desired project from the Projects menu in the navigation bar.
If it's not already displayed, click Clusters in the sidebar.
The Clusters page displays.
Start your index configuration.
Make the following selections on the page and then click Next.
Search Type | Select the Atlas Search index type. |
Index Name and Data Source | Specify the following information:
|
Configuration Method | For a guided experience, select Visual Editor. To edit the raw index definition, select JSON Editor. |
Note
Your Atlas Search index is named default
by default. If you keep this name, then your index will be the
default Search index for any Atlas Search query that does not specify a different index
option in
its operators. If you are creating multiple indexes, we recommend
that you maintain a consistent, descriptive naming convention across your indexes.
Specify an index definition.
The following index definition dynamically indexes the fields of supported types in the collection. You can use the Atlas Search Visual Editor or the Atlas Search JSON Editor in the Atlas user interface to create the index.
Review the "default"
index definition for the
collection.
Review the index definition.
Your index definition should look similar to the following example:
{ "mappings": { "dynamic": true } }
Run $unionWith
with $search
to Search the Collections
In this section, you will connect to your Atlas cluster and run
the sample query against the indexed collections in the
sample_training
database.
Connect to your cluster in mongosh
.
Open mongosh
in a terminal window and connect to your
cluster. For detailed instructions on connecting, see
Connect via mongosh
.
Switch to the sample_training
database.
Run the following command at mongosh
prompt:
use sample_training
switched to db sample_training
Run the following $unionWith
with an Atlas Search $search
query.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
db.companies.aggregate([ { "$search": { "text": { "query": "Mobile", "path": "name" } } }, { "$project": { "score": { "$meta": "searchScore" }, "_id": 0, "number_of_employees": 1, "founded_year": 1, "name": 1 } }, { "$set": { "source": "companies" } }, { "$limit": 3 }, { "$unionWith": { "coll": "inspections", "pipeline": [ { "$search": { "text": { "query": "Mobile", "path": "business_name" } } }, { "$set": { "source": "inspections" } }, { "$project": { "score": { "$meta": "searchScore" }, "source": 1, "_id": 0, "business_name": 1, "address": 1 } }, { "$limit": 3 }, { "$sort": { "score": -1 } } ] } } ])
[ { name: 'XLR8 Mobile', number_of_employees: 21, founded_year: 2006, score: 2.0815043449401855, source: 'companies' }, { name: 'Pulse Mobile', number_of_employees: null, founded_year: null, score: 2.0815043449401855, source: 'companies' }, { name: 'T-Mobile', number_of_employees: null, founded_year: null, score: 2.0815043449401855, source: 'companies' }, { business_name: 'T. MOBILE', address: { city: 'BROOKLYN', zip: 11209, street: '86TH ST', number: 440 }, score: 2.900916337966919, source: 'inspections' }, { business_name: 'BOOST MOBILE', address: { city: 'BRONX', zip: 10458, street: 'E FORDHAM RD', number: 261 }, score: 2.900916337966919, source: 'inspections' }, { business_name: 'SPRING MOBILE', address: { city: 'SOUTH RICHMOND HILL', zip: 11419, street: 'LIBERTY AVE', number: 12207 }, score: 2.900916337966919, source: 'inspections' } ]
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
db.companies.aggregate([ { "$search": { "text": { "query": "mobile", "path": "name", "score": { "boost": { "value": 1.6 } } } } }, { "$project": { "score": { "$meta": "searchScore" }, "_id": 0, "number_of_employees": 1, "founded_year": 1, "name": 1 } }, { "$addFields": { "source": "companies", "source_count": "$$SEARCH_META.count.lowerBound" } }, { "$limit": 3 }, { "$unionWith": { "coll": "inspections", "pipeline": [ { "$search": { "text": { "query": "mobile", "path": "business_name" } } }, { "$project": { "score": { "$meta": "searchScore" }, "business_name": 1, "address": 1, "_id": 0 } }, { "$limit": 3 }, { "$set": { "source": "inspections", "source_count": "$$SEARCH_META.count.lowerBound" } }, { "$sort": { "score": -1 } } ] } }, { "$facet": { "allDocs": [], "totalCount": [ { "$group": { "_id": "$source", "firstCount": { "$first": "$source_count" } } }, { "$project": { "totalCount": { "$sum": "$firstCount" } } } ] } } ])
[ { allDocs: [ { name: 'XLR8 Mobile', number_of_employees: 21, founded_year: 2006, score: 3.33040714263916, source: 'companies', source_count: Long("52") }, { name: 'Pulse Mobile', number_of_employees: null, founded_year: null, score: 3.33040714263916, source: 'companies', source_count: Long("52") }, { name: 'T-Mobile', number_of_employees: null, founded_year: null, score: 3.33040714263916, source: 'companies', source_count: Long("52") }, { business_name: 'T. MOBILE', address: { city: 'BROOKLYN', zip: 11209, street: '86TH ST', number: 440 }, score: 2.900916337966919, source: 'inspections', source_count: Long("456") }, { business_name: 'BOOST MOBILE', address: { city: 'BRONX', zip: 10458, street: 'E FORDHAM RD', number: 261 }, score: 2.900916337966919, source: 'inspections', source_count: Long("456") }, { business_name: 'SPRING MOBILE', address: { city: 'SOUTH RICHMOND HILL', zip: 11419, street: 'LIBERTY AVE', number: 12207 }, score: 2.900916337966919, source: 'inspections', source_count: Long("456") } ], totalCount: [ { _id: 'companies', totalCount: Long("52") }, { _id: 'inspections', totalCount: Long("456") } ] } ]
Connect to your cluster in MongoDB Compass.
Open MongoDB Compass and connect to your cluster. For detailed instructions on connecting, see Connect via Compass.
Run the Atlas Search query against the collection.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
To run this query in MongoDB Compass:
Click the Aggregations tab.
Click Select..., then configure each of the following pipeline stages by selecting the stage from the dropdown and adding the query for that stage. Click Add Stage to add additional stages.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
Pipeline StageQuery$search
{ "text": { "query": "Mobile", "path": "name" } } $project
{ "score": { "$meta": "searchScore", }, "_id": 0, "number_of_employees": 1, "founded_year": 1, "name": 1 } $set
{ "source": "companies" } $limit
3
$unionWith
{ "coll": "inspections", "pipeline": [ { "$search": { "text": { "query": "Mobile", "path": "business_name", } } }, { "$set": { "source": "inspections", } }, { "$project": { "score": { "$meta": "searchScore" }, "source": 1, "_id": 0, "business_name": 1, "address": 1 } }, { "$limit": 3 }, { "$sort": { "score": -1 } } ] } If you enabled Auto Preview, MongoDB Compass displays the following documents next to the
$project
pipeline stage:name: "XLR8 Mobile" number_of_employees: 21 founded_year: 2006 score: 2.0815043449401855 source: "companies" name: "Pulse Mobile" number_of_employees: null founded_year: null score: 2.0815043449401855 source: "companies" name: "T-Mobile" number_of_employees: null founded_year: null score: 2.0815043449401855 source: "companies" business_name: "T. MOBILE" address: Object source: "inspections" score: 2.900916337966919 business_name: "BOOST MOBILE" address: Object source: "inspections" score: 2.900916337966919 business_name: "SPRING MOBILE" address: Object source: "inspections" score: 2.900916337966919 This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
Pipeline StageQuery$search
{ text: { query: "mobile", path: "name", score: { boost: { value: 1.6 } } } } $project
{ "score": { "$meta": "searchScore", }, "_id": 0, "number_of_employees": 1, "founded_year": 1, "name": 1 } $addFields
{ source: "companies", source_count: "$$SEARCH_META.count.lowerBound" } $limit
3
$unionWith
{ coll: "inspections", pipeline: [ { $search: { text: { query: "mobile", path: "business_name" } } }, { $project: { score: { $meta: "searchScore" }, business_name: 1, address: 1, _id: 0 } }, { $limit: 3, }, { $set: { source: "inspections", source_count: "$$SEARCH_META.count.lowerBound" } }, { $sort: { score: -1 } } ] } $facet
{ allDocs: [], totalCount: [ { $group: { _id: "$source", firstCount: { $first: "$source_count" } } }, { $project: { totalCount: { $sum: "$firstCount" } } } ] } If you enabled Auto Preview, MongoDB Compass displays the following documents next to the
$project
pipeline stage:allDocs: Array (6) 0: Object name: "XLR8 Mobile" number_of_employees: 21 founded_year: 2006 score: 3.33040714263916 source: "companies" source_count: 52 1: Object name: "Pulse Mobile" number_of_employees: null founded_year: null score: 3.33040714263916 source: "companies" source_count: 52 2: Object name: "T-Mobile" number_of_employees: null founded_year: null score: 3.33040714263916 source: "companies" source_count: 52 3: Object business_name: "T. MOBILE" address: Object score: 2.900916337966919 source: "inspections" source_count: 456 4: Object business_name: "BOOST MOBILE" address: Object score: 2.900916337966919 source: "inspections" source_count: 456 5: Object business_name: "SPRING MOBILE" address: Object score: 2.900916337966919 source: "inspections" source_count: 456 totalCount: Array (2) 0: Object _id: "companies" totalCount: 52 1: Object _id: "inspections" totalCount: 456
Set up and initialize the .NET/C# project for the query.
Create a new directory called
search-with-unionwith
and initialize your project with the dotnet new command.mkdir search-with-unionwith cd search-with-unionwith dotnet new console Add the .NET/C# Driver to your project as a dependency.
dotnet add package MongoDB.Driver
Copy and paste the query into the Program.cs
file.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
1 using MongoDB.Bson; 2 using MongoDB.Driver; 3 using MongoDB.Driver.Search; 4 5 public class Program 6 { 7 public static void Main(string[] args) 8 { 9 // connect to your Atlas cluster 10 string connectionString = "<connection-string>"; 11 var client = new MongoClient(connectionString); 12 13 // define namespace 14 var database = client.GetDatabase("sample_training"); 15 var collection = database.GetCollection<BsonDocument>("companies"); 16 17 // define pipeline stage 18 var searchStage1 = new BsonDocument("$search", new BsonDocument{{ "text", new BsonDocument 19 {{ "query", "Mobile" },{ "path", "name" }} 20 }}); 21 var projectStage1 = new BsonDocument("$project", new BsonDocument{ 22 { "score", new BsonDocument("$meta", "searchScore") }, 23 { "_id", 0 },{ "number_of_employees", 1 },{ "founded_year", 1 },{ "name", 1 } 24 }); 25 var setStage1 = new BsonDocument("$set", new BsonDocument{{ "source", "companies" }}); 26 var limitStage1 = new BsonDocument("$limit", 3); 27 28 // define subpipeline 29 var searchStage2 = new BsonDocument("$search", new BsonDocument{{ "text", new BsonDocument 30 {{ "query", "Mobile" },{ "path", "business_name" }} 31 }}); 32 var setStage2 = new BsonDocument("$set", new BsonDocument{ { "source", "inspections" } }); 33 var projectStage2 = new BsonDocument("$project", new BsonDocument{ 34 { "score", new BsonDocument("$meta", "searchScore") }, 35 { "source", 1 }, { "_id", 0 }, { "business_name", 1 }, { "address", 1 } 36 }); 37 var limitStage2 = new BsonDocument("$limit", 3); 38 var sortStage2 = new BsonDocument("$sort", new BsonDocument{{ "score", -1 }}); 39 var unionWithPipeline = new List<BsonDocument>{searchStage2, setStage2, projectStage2, limitStage2, sortStage2}; 40 var unionWithStage = new BsonDocument("$unionWith", new BsonDocument 41 { 42 { "coll", "inspections" }, 43 { "pipeline", new BsonArray(unionWithPipeline) } 44 }); 45 var aggregationPipeline = new List<BsonDocument> {searchStage1, projectStage1, setStage1, limitStage1,unionWithStage}; 46 47 // run pipeline 48 var result = collection.Aggregate<BsonDocument>(aggregationPipeline).ToList(); 49 50 //print results 51 foreach (var document in result) 52 { 53 Console.WriteLine(document); 54 } 55 } 56 }
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
1 using MongoDB.Bson; 2 using MongoDB.Driver; 3 4 public class Program 5 { 6 public static void Main(string[] args) 7 { 8 // connect to your Atlas cluster 9 var client = new MongoClient("<connection-string>"); 10 11 // define namespace 12 var database = client.GetDatabase("sample_training"); 13 var collection = database.GetCollection<BsonDocument>("companies"); 14 15 // define pipeline 16 var pipeline = new BsonDocument[] 17 { 18 new BsonDocument("$search", new BsonDocument{ 19 { "text", new BsonDocument{ 20 { "query", "mobile" }, { "path", "name" }, 21 { "score", new BsonDocument{ 22 { "boost", new BsonDocument{ { "value", 1.6 } }} 23 }} 24 }} 25 }), 26 new BsonDocument("$project", new BsonDocument{ 27 { "score", new BsonDocument("$meta", "searchScore") }, 28 { "_id", 0 }, 29 { "number_of_employees", 1 }, { "founded_year", 1 }, { "name", 1 } 30 }), 31 new BsonDocument("$addFields", new BsonDocument{ 32 { "source", "companies" }, 33 { "source_count", "$$SEARCH_META.count.lowerBound" } 34 }), 35 new BsonDocument("$limit", 3), 36 new BsonDocument("$unionWith", new BsonDocument{ 37 { "coll", "inspections" }, 38 { "pipeline", new BsonArray{ 39 new BsonDocument("$search", new BsonDocument{ 40 { "text", new BsonDocument{ 41 { "query", "mobile" }, 42 { "path", "business_name" } 43 }} 44 }), 45 new BsonDocument("$project", new BsonDocument{ 46 { "score", new BsonDocument("$meta", "searchScore") }, 47 { "business_name", 1 }, { "address", 1 }, { "_id", 0 } 48 }), 49 new BsonDocument("$limit", 3), 50 new BsonDocument("$set", new BsonDocument{ 51 { "source", "inspections" }, 52 { "source_count", "$$SEARCH_META.count.lowerBound" } 53 }), 54 new BsonDocument("$sort", new BsonDocument{ 55 { "score", -1 } 56 }) 57 }} 58 }), 59 new BsonDocument("$facet", new BsonDocument{ 60 { "allDocs", new BsonArray() }, 61 { "totalCount", new BsonArray{ 62 new BsonDocument("$group", new BsonDocument{ 63 { "_id", "$source" }, 64 { "firstCount", new BsonDocument("$first", "$source_count") } 65 }), 66 new BsonDocument("$project", new BsonDocument{ 67 { "totalCount", new BsonDocument("$sum", "$firstCount") } 68 }) 69 }} 70 }) 71 }; 72 73 // run pipeline 74 var result = collection.Aggregate<BsonDocument>(pipeline).ToList(); 75 76 //print results 77 foreach (var document in result) 78 { 79 Console.WriteLine(document); 80 } 81 } 82 }
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Compile and run the Program.cs
file.
dotnet run search-with-unionwith.csproj
{ "name" : "XLR8 Mobile", "number_of_employees" : 21, "founded_year" : 2006, "score" : 2.0815043449401855, "source" : "companies" } { "name" : "Pulse Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 2.0815043449401855, "source" : "companies" } { "name" : "T-Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 2.0815043449401855, "source" : "companies" } { "business_name" : "T. MOBILE", "address" : { "city" : "BROOKLYN", "zip" : 11209, "street" : "86TH ST", "number" : 440 }, "source" : "inspections", "score" : 2.9009163379669189 } { "business_name" : "BOOST MOBILE", "address" : { "city" : "BRONX", "zip" : 10458, "street" : "E FORDHAM RD", "number" : 261 }, "source" : "inspections", "score" : 2.9009163379669189 } { "business_name" : "SPRING MOBILE", "address" : { "city" : "SOUTH RICHMOND HILL", "zip" : 11419, "street" : "LIBERTY AVE", "number" : 12207 }, "source" : "inspections", "score" : 2.9009163379669189 }
dotnet run search-with-unionwith.csproj
{ "allDocs" : [ { "name" : "XLR8 Mobile", "number_of_employees" : 21, "founded_year" : 2006, "score" : 3.3304071426391602, "source" : "companies", "source_count" : NumberLong(52) }, { "name" : "Pulse Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 3.3304071426391602, "source" : "companies", "source_count" : NumberLong(52) }, { "name" : "T-Mobile", "number_of_employees" : null, "founded_year" : null, "score" : 3.3304071426391602, "source" : "companies", "source_count" : NumberLong(52) }, { "business_name" : "T. MOBILE", "address" : { "city" : "BROOKLYN", "zip" : 11209, "street" : "86TH ST", "number" : 440 }, "score" : 2.9009163379669189, "source" : "inspections", "source_count" : NumberLong(456) }, { "business_name" : "BOOST MOBILE", "address" : { "city" : "BRONX", "zip" : 10458, "street" : "E FORDHAM RD", "number" : 261 }, "score" : 2.9009163379669189, "source" : "inspections", "source_count" : NumberLong(456) }, { "business_name" : "SPRING MOBILE", "address" : { "city" : "SOUTH RICHMOND HILL", "zip" : 11419, "street" : "LIBERTY AVE", "number" : 12207 }, "score" : 2.9009163379669189, "source" : "inspections", "source_count" : NumberLong(456) } ], "totalCount" : [ { "_id" : "companies", "totalCount" : NumberLong(52) }, { "_id" : "inspections", "totalCount" : NumberLong(456) } ] }
Copy and paste the query into the search-with-unionwith-query.go
file.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.mongodb.org/mongo-driver/v2/bson" 9 "go.mongodb.org/mongo-driver/v2/mongo" 10 "go.mongodb.org/mongo-driver/v2/mongo/options" 11 ) 12 13 func main() { 14 // connect to the Atlas cluster and set a maximum operation time 15 ctx := context.Background() 16 opts := options.Client(). 17 SetTimeout(5 * time.Second). 18 ApplyURI("<connection-string>") 19 20 client, err := mongo.Connect(opts) 21 if err != nil { 22 panic(err) 23 } 24 defer client.Disconnect(ctx) 25 26 // set namespace 27 collection := client.Database("sample_training").Collection("companies") 28 // define pipeline 29 searchStage := bson.D{{"$search", bson.D{ 30 {"text", bson.D{ 31 {"query", "Mobile"}, {"path", "name"}, 32 }}, 33 }}} 34 projectStage := bson.D{{"$project", bson.D{ 35 {"score", bson.D{{"$meta", "searchScore"}}}, 36 {"_id", 0}, 37 {"number_of_employees", 1}, 38 {"founded_year", 1}, 39 {"name", 1}, 40 }}} 41 setStage := bson.D{{"$set", bson.D{{"source", "companies"}}}} 42 limitStage := bson.D{{"$limit", 5}} 43 unionWithStage := bson.D{{"$unionWith", bson.D{ 44 {"coll", "inspections"}, 45 {"pipeline", bson.A{ 46 bson.D{{"$search", bson.D{ 47 {"text", bson.D{ 48 {"query", "Mobile"}, {"path", "business_name"}, 49 }}, 50 }}}, 51 bson.D{{"$set", bson.D{{"source", "inspections"}}}}, 52 bson.D{{"$project", bson.D{ 53 {"score", bson.D{{"$meta", "searchScore"}}}, 54 {"source", 1}, 55 {"_id", 0}, 56 {"business_name", 1}, 57 {"address", 1}, 58 }}}, 59 bson.D{{"$limit", 3}}, 60 bson.D{{"$sort", bson.D{{"score", -1}}}}, 61 }}, 62 }}} 63 // run pipeline 64 cursor, err := collection.Aggregate(ctx, mongo.Pipeline{searchStage, projectStage, setStage, limitStage, unionWithStage}) 65 if err != nil { 66 panic(err) 67 } 68 // print results 69 var results []bson.D 70 if err = cursor.All(context.TODO(), &results); err != nil { 71 panic(err) 72 } 73 for _, result := range results { 74 fmt.Println(result) 75 } 76 }
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.mongodb.org/mongo-driver/v2/bson" 9 "go.mongodb.org/mongo-driver/v2/mongo" 10 "go.mongodb.org/mongo-driver/v2/mongo/options" 11 ) 12 13 func main() { 14 // connect to the Atlas cluster and set a maximum operation time 15 ctx := context.Background() 16 opts := options.Client(). 17 SetTimeout(5 * time.Second). 18 ApplyURI("<connection-string>") 19 20 client, err := mongo.Connect(opts) 21 if err != nil { 22 panic(err) 23 } 24 defer client.Disconnect(ctx) 25 // set namespace 26 collection := client.Database("sample_training").Collection("companies") 27 // define pipeline 28 searchStage := bson.D{{"$search", bson.D{ 29 {"text", bson.D{ 30 {"query", "Mobile"}, {"path", "name"}, {"score", bson.D{{"boost", bson.D{{"value", 1.6}}}}}, 31 }}, 32 }}} 33 projectStage := bson.D{{"$project", bson.D{ 34 {"score", bson.D{{"$meta", "searchScore"}}}, 35 {"_id", 0}, 36 {"number_of_employees", 1}, 37 {"founded_year", 1}, 38 {"name", 1}, 39 }}} 40 addFieldsStage := bson.D{{"$set", bson.D{ 41 {"source", "companies"}, 42 {"source_count", "$$SEARCH_META.count.lowerBound"}, 43 }}} 44 limitStage := bson.D{{"$limit", 3}} 45 unionWithStage := bson.D{{"$unionWith", bson.D{ 46 {"coll", "inspections"}, 47 {"pipeline", bson.A{ 48 bson.D{{"$search", bson.D{ 49 {"text", bson.D{ 50 {"query", "mobile"}, {"path", "business_name"}, 51 }}, 52 }}}, 53 bson.D{{"$project", bson.D{ 54 {"score", bson.D{{"$meta", "searchScore"}}}, 55 {"business_name", 1}, 56 {"address", 1}, 57 {"_id", 0}, 58 }}}, 59 bson.D{{"$limit", 3}}, 60 bson.D{{"$set", bson.D{ 61 {"source", "inspections"}, 62 {"source_count", "$$SEARCH_META.count.lowerBound"}, 63 }}}, 64 bson.D{{"$sort", bson.D{{"score", -1}}}}, 65 }}, 66 }}} 67 facetStage := bson.D{{"$facet", bson.D{ 68 {"allDocs", bson.A{}}, 69 {"totalCount", bson.A{ 70 bson.D{ 71 {"$group", bson.D{ 72 {"_id", "$source"}, 73 {"firstCount", bson.D{{"$first", "$source_count"}}}, 74 }}, 75 }, 76 bson.D{{"$project", bson.D{{"totalCount", bson.D{{"$sum", "$firstCount"}}}}}}, 77 }}, 78 }}} 79 // run pipeline 80 cursor, err := collection.Aggregate(ctx, mongo.Pipeline{searchStage, projectStage, addFieldsStage, limitStage, unionWithStage, facetStage}) 81 if err != nil { 82 panic(err) 83 } 84 // print results 85 var results []bson.D 86 if err = cursor.All(context.TODO(), &results); err != nil { 87 panic(err) 88 } 89 for _, result := range results { 90 fmt.Println(result) 91 } 92 }
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Run the command to query your collection.
go run search-with-unionwith-query.go
[{name XLR8 Mobile} {number_of_employees 21} {founded_year 2006} {score 3.33040714263916} {source companies} {source_count 52}] [{name Pulse Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}] [{name T-Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}] [{business_name T. MOBILE} {address [{city BROOKLYN} {zip 11209} {street 86TH ST} {number 440}]} {score 2.900916337966919} {source inspections} {source_count 456}] [{business_name BOOST MOBILE} {address [{city BRONX} {zip 10458} {street E FORDHAM RD} {number 261}]} {score 2.900916337966919} {source inspections} {source_count 456}] [{business_name SPRING MOBILE} {address [{city SOUTH RICHMOND HILL} {zip 11419} {street LIBERTY AVE} {number 12207}]} {score 2.900916337966919} {source inspections} {source_count 456}]
go run search-with-unionwith-query.go
[ {allDocs [ [{name XLR8 Mobile} {number_of_employees 21} {founded_year 2006} {score 3.33040714263916} {source companies} {source_count 52}] [{name Pulse Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}] [{name T-Mobile} {number_of_employees <nil>} {founded_year <nil>} {score 3.33040714263916} {source companies} {source_count 52}] [{business_name T. MOBILE} {address [{city BROOKLYN} {zip 11209} {street 86TH ST} {number 440}]} {score 2.900916337966919} {source inspections} {source_count 456}] [{business_name BOOST MOBILE} {address [{city BRONX} {zip 10458} {street E FORDHAM RD} {number 261}]} {score 2.900916337966919} {source inspections} {source_count 456}] [{business_name SPRING MOBILE} {address [{city SOUTH RICHMOND HILL} {zip 11419} {street LIBERTY AVE} {number 12207}]} {score 2.900916337966919} {source inspections} {source_count 456}] ]} {totalCount [ [{_id inspections} {totalCount 456}] [{_id companies} {totalCount 52}] ]} ]
Copy and paste the query into the SearchWithUnionwithQuery.java
file.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
1 import com.mongodb.client.MongoClients; 2 import com.mongodb.client.MongoClient; 3 import com.mongodb.client.MongoDatabase; 4 import org.bson.Document; 5 import java.util.ArrayList; 6 import java.util.Arrays; 7 import java.util.List; 8 9 public class SearchWithUnionwith { 10 public static void main(String[] args) { 11 // connect to Atlas cluster 12 try (MongoClient mongoClient = MongoClients.create("<connection-string>")) { 13 // get database name 14 MongoDatabase database = mongoClient.getDatabase("sample_training"); 15 // define pipeline 16 List<Document> pipeline1 = Arrays.asList( 17 new Document("$search", new Document("text", 18 new Document("query", "Mobile") 19 .append("path", "name"))), 20 new Document("$project", new Document("score", 21 new Document("$meta", "searchScore")) 22 .append("_id", 0) 23 .append("number_of_employees", 1) 24 .append("founded_year", 1) 25 .append("name", 1)), 26 new Document("$set", new Document("source", "companies")), 27 new Document("$limit", 3) 28 ); 29 30 List<Document> pipeline2 = Arrays.asList( 31 new Document("$search", new Document("text", 32 new Document("query", "Mobile") 33 .append("path", "business_name"))), 34 new Document("$set", new Document("source", "inspections")), 35 new Document("$project", new Document("score", 36 new Document("$meta", "searchScore")) 37 .append("source", 1) 38 .append("_id", 0) 39 .append("business_name", 1) 40 .append("address", 1)), 41 new Document("$limit", 3), 42 new Document("$sort", new Document("score", -1)) 43 ); 44 45 List<Document> unionWithStage = new ArrayList<>(); 46 Document unionWith = new Document("$unionWith", new Document("coll", "inspections") 47 .append("pipeline", pipeline2)); 48 unionWithStage.add(unionWith); 49 50 List<Document> finalPipeline = new ArrayList<>(pipeline1); 51 finalPipeline.addAll(unionWithStage); 52 // run pipeline and print results 53 database.getCollection("companies").aggregate(finalPipeline) 54 .forEach(doc -> System.out.println(doc.toJson())); 55 } 56 } 57 }
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
1 import com.mongodb.client.MongoClients; 2 import com.mongodb.client.MongoCollection; 3 import com.mongodb.client.MongoClient; 4 import org.bson.Document; 5 6 public class SearchWithUnionwith { 7 public static void main(String[] args) { 8 // connect to Atlas cluster 9 try (MongoClient mongoClient = MongoClients.create("<connection-string>")) { 10 // define namespace 11 MongoCollection<Document> collection = mongoClient.getDatabase("sample_training").getCollection("companies"); 12 // define pipeline 13 Document searchStage = new Document("$search", new Document("text", 14 new Document("query", "mobile") 15 .append("path", "name") 16 .append("score", new Document("boost", new Document("value", 1.6))) 17 ) 18 ); 19 20 Document projectStage = new Document("$project", new Document("score", new Document("$meta", "searchScore")) 21 .append("_id", 0) 22 .append("number_of_employees", 1) 23 .append("founded_year", 1) 24 .append("name", 1) 25 ); 26 27 Document addFieldsStage = new Document("$addFields", new Document("source", "companies") 28 .append("source_count", "$$SEARCH_META.count.lowerBound") 29 ); 30 31 Document limitStage = new Document("$limit", 3); 32 33 Document unionWithStage = new Document("$unionWith", new Document("coll", "inspections") 34 .append("pipeline", java.util.Arrays.asList( 35 new Document("$search", new Document("text", 36 new Document("query", "mobile") 37 .append("path", "business_name") 38 )), 39 new Document("$project", new Document("score", new Document("$meta", "searchScore")) 40 .append("business_name", 1) 41 .append("address", 1) 42 .append("_id", 0) 43 ), 44 new Document("$limit", 3), 45 new Document("$set", new Document("source", "inspections") 46 .append("source_count", "$$SEARCH_META.count.lowerBound") 47 ), 48 new Document("$sort", new Document("score", -1)) 49 )) 50 ); 51 52 Document facetStage = new Document("$facet", new Document("allDocs", java.util.Arrays.asList()) 53 .append("totalCount", java.util.Arrays.asList( 54 new Document("$group", new Document("_id", "$source") 55 .append("firstCount", new Document("$first", "$source_count")) 56 ), 57 new Document("$project", new Document("totalCount", 58 new Document("$sum", "$firstCount") 59 )) 60 )) 61 ); 62 // run pipeline and print results 63 collection.aggregate(java.util.Arrays.asList( 64 searchStage, projectStage, addFieldsStage, limitStage, unionWithStage, facetStage 65 )).forEach(doc -> System.out.println(doc.toJson())); 66 } 67 } 68 }
Note
To run the sample code in your Maven environment, add the following code above the import statements in your file.
package com.mongodb.drivers;
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Compile and run the UinionwithWithSearchQuery.java
file.
javac SearchWithUnionwithQuery.java java SearchWithUnionwithQuery
{"name": "XLR8 Mobile", "number_of_employees": 21, "founded_year": 2006, "score": 2.0815043449401855, "source": "companies"} {"name": "Pulse Mobile", "number_of_employees": null, "founded_year": null, "score": 2.0815043449401855, "source": "companies"} {"name": "T-Mobile", "number_of_employees": null, "founded_year": null, "score": 2.0815043449401855, "source": "companies"} {"business_name": "T. MOBILE", "address": {"city": "BROOKLYN", "zip": 11209, "street": "86TH ST", "number": 440}, "source": "inspections", "score": 2.900916337966919} {"business_name": "BOOST MOBILE", "address": {"city": "BRONX", "zip": 10458, "street": "E FORDHAM RD", "number": 261}, "source": "inspections", "score": 2.900916337966919} {"business_name": "SPRING MOBILE", "address": {"city": "SOUTH RICHMOND HILL", "zip": 11419, "street": "LIBERTY AVE", "number": 12207}, "source": "inspections", "score": 2.900916337966919}
javac SearchWithUnionwithQuery.java java SearchWithUnionwithQuery
{ "allDocs": [ {"name": "XLR8 Mobile", "number_of_employees": 21, "founded_year": 2006, "score": 3.33040714263916, "source": "companies", "source_count": 52}, {"name": "Pulse Mobile", "number_of_employees": null, "founded_year": null, "score": 3.33040714263916, "source": "companies", "source_count": 52}, {"name": "T-Mobile", "number_of_employees": null, "founded_year": null, "score": 3.33040714263916, "source": "companies", "source_count": 52}, {"business_name": "T. MOBILE", "address": {"city": "BROOKLYN", "zip": 11209, "street": "86TH ST", "number": 440}, "score": 2.900916337966919, "source": "inspections", "source_count": 456}, {"business_name": "BOOST MOBILE", "address": {"city": "BRONX", "zip": 10458, "street": "E FORDHAM RD", "number": 261}, "score": 2.900916337966919, "source": "inspections", "source_count": 456}, {"business_name": "SPRING MOBILE", "address": {"city": "SOUTH RICHMOND HILL", "zip": 11419, "street": "LIBERTY AVE", "number": 12207}, "score": 2.900916337966919, "source": "inspections", "source_count": 456} ], "totalCount": [ {"_id": "companies", "totalCount": 52}, {"_id": "inspections", "totalCount": 456} ] }
Copy and paste the query into the SearchWithUnionwithQuery.kt
file.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
1 import com.mongodb.kotlin.client.coroutine.MongoClient 2 import kotlinx.coroutines.runBlocking 3 import org.bson.Document 4 5 fun main() { 6 // connect to Atlas cluster 7 val uri = "<connection-string>" 8 val mongoClient = MongoClient.create(uri) 9 10 // set namespace 11 val database = mongoClient.getDatabase("sample_training") 12 val collection = database.getCollection<Document>("companies") 13 14 runBlocking { 15 // define pipeline 16 val pipeline1 = listOf( 17 Document("\$search", Document("text", 18 Document("query", "Mobile") 19 .append("path", "name"))), Document("\$project", Document("score", 20 Document("\$meta", "searchScore")) 21 .append("_id", 0) 22 .append("number_of_employees", 1) 23 .append("founded_year", 1) 24 .append("name", 1)), Document("\$set", Document("source", "companies")), 25 Document("\$limit", 3) 26 ) 27 28 val pipeline2 = listOf( 29 Document( 30 "\$search", Document( 31 "text", 32 Document("query", "Mobile") 33 .append("path", "business_name") 34 ) 35 ), 36 Document("\$set", Document("source", "inspections")), 37 Document( 38 "\$project", Document( 39 "score", 40 Document("\$meta", "searchScore") 41 ) 42 .append("source", 1) 43 .append("_id", 0) 44 .append("business_name", 1) 45 .append("address", 1) 46 ), 47 Document("\$limit", 3), 48 Document("\$sort", Document("score", -1)) 49 ) 50 51 val unionWithStage: MutableList<Document> = ArrayList() 52 val unionWith = Document( 53 "\$unionWith", Document("coll", "inspections") 54 .append("pipeline", pipeline2) 55 ) 56 unionWithStage.add(unionWith) 57 val finalPipeline: MutableList<Document> = ArrayList(pipeline1) 58 finalPipeline.addAll(unionWithStage) 59 60 // run pipeline and print results 61 val resultsFlow = collection.aggregate<Document>(finalPipeline) 62 resultsFlow.collect { println(it) } 63 64 } 65 mongoClient.close() 66 }
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
1 import com.mongodb.kotlin.client.coroutine.MongoClient 2 import kotlinx.coroutines.runBlocking 3 import org.bson.Document 4 import java.util.* 5 6 fun main() { 7 // connect to Atlas cluster 8 val uri = "<connection-string>" 9 val mongoClient = MongoClient.create(uri) 10 11 // set namespace 12 val database = mongoClient.getDatabase("sample_training") 13 val collection = database.getCollection<Document>("companies") 14 15 runBlocking { 16 // define pipeline stages 17 val searchStage = Document( 18 "\$search", Document( 19 "text", 20 Document("query", "mobile") 21 .append("path", "name") 22 .append("score", Document("boost", Document("value", 1.6))) 23 ) 24 ) 25 26 val projectStage = Document( 27 "\$project", Document("score", Document("\$meta", "searchScore")) 28 .append("_id", 0) 29 .append("number_of_employees", 1) 30 .append("founded_year", 1) 31 .append("name", 1) 32 ) 33 34 val addFieldsStage = Document( 35 "\$addFields", Document("source", "companies") 36 .append("source_count", "$\$SEARCH_META.count.lowerBound") 37 ) 38 39 val limitStage = Document("\$limit", 3) 40 41 val unionWithStage = Document( 42 "\$unionWith", Document("coll", "inspections") 43 .append( 44 "pipeline", Arrays.asList( 45 Document( 46 "\$search", Document( 47 "text", 48 Document("query", "mobile") 49 .append("path", "business_name") 50 ) 51 ), 52 Document( 53 "\$project", Document("score", Document("\$meta", "searchScore")) 54 .append("business_name", 1) 55 .append("address", 1) 56 .append("_id", 0) 57 ), 58 Document("\$limit", 3), 59 Document( 60 "\$set", Document("source", "inspections") 61 .append("source_count", "$\$SEARCH_META.count.lowerBound") 62 ), 63 Document("\$sort", Document("score", -1)) 64 ) 65 ) 66 ) 67 68 val facetStage = Document( 69 "\$facet", Document("allDocs", Arrays.asList<Any>()) 70 .append( 71 "totalCount", Arrays.asList( 72 Document( 73 "\$group", Document("_id", "\$source") 74 .append("firstCount", Document("\$first", "\$source_count")) 75 ), 76 Document( 77 "\$project", Document( 78 "totalCount", 79 Document("\$sum", "\$firstCount") 80 ) 81 ) 82 ) 83 ) 84 ) 85 86 // run pipeline and print results 87 val resultsFlow = collection.aggregate<Document>( 88 listOf( 89 searchStage, 90 projectStage, 91 addFieldsStage, 92 limitStage, 93 unionWithStage, 94 facetStage 95 ) 96 ) 97 resultsFlow.collect { println(it) } 98 99 } 100 mongoClient.close() 101 }
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Run the SearchWithUnionwithQuery.kt
file.
When you run the SearchWithUnionwithQuery.kt
program in your IDE, it prints
the following documents:
Document{{name=XLR8 Mobile, number_of_employees=21, founded_year=2006, score=2.0815043449401855, source=companies}} Document{{name=Pulse Mobile, number_of_employees=null, founded_year=null, score=2.0815043449401855, source=companies}} Document{{name=Mobile Trend, number_of_employees=null, founded_year=2003, score=2.0815043449401855, source=companies}} Document{{business_name=T-MOBILE, address=Document{{city=BROOKLYN, zip=11229, street=AVENUE U, number=1616}}, source=inspections, score=2.900916337966919}} Document{{business_name=BOOST MOBILE, address=Document{{city=BRONX, zip=10458, street=E FORDHAM RD, number=261}}, source=inspections, score=2.900916337966919}} Document{{business_name=SPRING MOBILE, address=Document{{city=SOUTH RICHMOND HILL, zip=11419, street=LIBERTY AVE, number=12207}}, source=inspections, score=2.900916337966919}}
When you run the SearchWithUnionwithQuery.kt
program in your IDE, it prints
the following result:
Document{{allDocs=[Document{{name=XLR8 Mobile, number_of_employees=21, founded_year=2006, score=3.33040714263916, source=companies, source_count=52}}, Document{{name=Pulse Mobile, number_of_employees=null, founded_year=null, score=3.33040714263916, source=companies, source_count=52}}, Document{{name=Mobile Trend, number_of_employees=null, founded_year=2003, score=3.33040714263916, source=companies, source_count=52}}, Document{{business_name=T-MOBILE, address=Document{{city=BROOKLYN, zip=11229, street=AVENUE U, number=1616}}, score=2.900916337966919, source=inspections, source_count=456}}, Document{{business_name=BOOST MOBILE, address=Document{{city=BRONX, zip=10458, street=E FORDHAM RD, number=261}}, score=2.900916337966919, source=inspections, source_count=456}}, Document{{business_name=SPRING MOBILE, address=Document{{city=SOUTH RICHMOND HILL, zip=11419, street=LIBERTY AVE, number=12207}}, score=2.900916337966919, source=inspections, source_count=456}}], totalCount=[Document{{_id=inspections, totalCount=456}}, Document{{_id=companies, totalCount=52}}]}}
Copy and paste the sample query into the search-with-unionwith-query.js
file.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
1 const MongoClient = require("mongodb").MongoClient; 2 const assert = require("assert"); 3 4 const agg = [ 5 { 6 '$search': { 7 'text': { 'query': 'Mobile', 'path': 'name' } 8 } 9 }, { 10 '$project': { 11 'score': { '$meta': 'searchScore' }, 12 '_id': 0, 'number_of_employees': 1, 'founded_year': 1, 'name': 1 13 } 14 }, { 15 '$set': { 'source': 'companies' } 16 }, { 17 '$limit': 3 18 }, { 19 '$unionWith': { 20 'coll': 'inspections', 21 'pipeline': [ 22 { 23 '$search': { 24 'text': { 'query': 'Mobile', 'path': 'business_name' } 25 } 26 }, { 27 '$set': { 'source': 'inspections' } 28 }, { 29 '$project': { 30 'score': { '$meta': 'searchScore' }, 31 'source': 1, '_id': 0, 'business_name': 1, 'address': 1 32 } 33 }, { 34 '$limit': 3 35 }, { 36 '$sort': { 'score': -1 } 37 } 38 ] 39 } 40 } 41 ]; 42 43 MongoClient.connect( 44 "<connection-string>", 45 { useNewUrlParser: true, useUnifiedTopology: true }, 46 async function (connectErr, client) { 47 assert.equal(null, connectErr); 48 const coll = client.db("sample_training").collection("companies"); 49 let cursor = await coll.aggregate(agg); 50 await cursor.forEach((doc) => console.log(doc)); 51 client.close(); 52 } 53 );
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
1 const MongoClient = require("mongodb").MongoClient; 2 const assert = require("assert"); 3 4 const agg = [ 5 {'$search': { 'text': { 6 'query': 'mobile', 7 'path': 'name', 8 'score': { 9 'boost': { 'value': 1.6 } 10 } 11 }}}, 12 {'$project': { 13 'score': { '$meta': 'searchScore' }, 14 '_id': 0, 15 'number_of_employees': 1, 16 'founded_year': 1, 17 'name': 1 18 }}, 19 {'$addFields': { 20 'source': 'companies', 21 'source_count': '$$SEARCH_META.count.lowerBound' 22 }}, 23 {'$limit': 3}, 24 {'$unionWith': { 25 'coll': 'inspections', 26 'pipeline': [ 27 {'$search': { 28 'text': { 'query': 'mobile', 'path': 'business_name' } 29 }}, 30 {'$project': { 31 'score': { '$meta': 'searchScore' }, 32 'business_name': 1, 33 'address': 1, 34 '_id': 0 35 }}, 36 {'$limit': 3}, 37 {'$set': { 38 'source': 'inspections', 39 'source_count': '$$SEARCH_META.count.lowerBound' 40 }}, 41 {'$sort': { 'score': -1 } } 42 ] 43 }}, 44 {'$facet': { 45 'allDocs': [], 46 'totalCount': [ 47 {'$group': { 48 '_id': '$source', 49 'firstCount': { '$first': '$source_count' } 50 }}, 51 {'$project': { 52 'totalCount': { '$sum': '$firstCount' } 53 }} 54 ] 55 }} 56 ]; 57 58 MongoClient.connect( 59 "<connection-string>", 60 { useNewUrlParser: true, useUnifiedTopology: true }, 61 async function (connectErr, client) { 62 assert.equal(null, connectErr); 63 const coll = client.db("sample_training").collection("companies"); 64 let cursor = await coll.aggregate(agg); 65 await cursor.forEach((doc) => console.log(doc)); 66 client.close(); 67 } 68 );
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Query your collection.
Run the following command to query your collection:
node unionwith-with-search-query.js
{ name: 'SoftBank Mobile', number_of_employees: null, founded_year: null, score: 2.0815043449401855, source: 'companies' } { name: 'Mobile Factory', number_of_employees: 53, founded_year: 2001, score: 2.0815043449401855, source: 'companies' } { name: 'ZOOZ Mobile', number_of_employees: 5, founded_year: 2008, score: 2.0815043449401855, source: 'companies' } { business_name: 'T. MOBILE', address: { city: 'BROOKLYN', zip: 11209, street: '86TH ST', number: 440 }, source: 'inspections', score: 2.900916337966919 } { business_name: 'BOOST MOBILE', address: { city: 'BRONX', zip: 10458, street: 'E FORDHAM RD', number: 261 }, source: 'inspections', score: 2.900916337966919 } { business_name: 'T-MOBILE', address: { city: 'BROOKLYN', zip: 11229, street: 'AVENUE U', number: 1616 }, source: 'inspections', score: 2.900916337966919 }
node unionwith-with-search-query.js
{ allDocs: [ { name: 'XLR8 Mobile', number_of_employees: 21, founded_year: 2006, score: 3.33040714263916, source: 'companies', source_count: 52 }, { name: 'Pulse Mobile', number_of_employees: null, founded_year: null, score: 3.33040714263916, source: 'companies', source_count: 52 }, { name: 'T-Mobile', number_of_employees: null, founded_year: null, score: 3.33040714263916, source: 'companies', source_count: 52 }, { business_name: 'T. MOBILE', address: [Object], score: 2.900916337966919, source: 'inspections', source_count: 456 }, { business_name: 'BOOST MOBILE', address: [Object], score: 2.900916337966919, source: 'inspections', source_count: 456 }, { business_name: 'SPRING MOBILE', address: [Object], score: 2.900916337966919, source: 'inspections', source_count: 456 } ], totalCount: [ { _id: 'companies', totalCount: 52 }, { _id: 'inspections', totalCount: 456 } ] }
Copy and paste the query into the search-with-unionwith-query.py
file.
The following query searches both the companies
and
inspections
collections for the term mobile
in the name
and business_name
fields respectively.
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$set
stage to add a new field namedsource
that identifies the collection of the output documents.
1 import pymongo 2 import dns 3 4 client = pymongo.MongoClient('<connection-string>') 5 result = client['sample_training']['companies'].aggregate([ 6 { 7 '$search': { 8 'text': { 'query': 'Mobile', 'path': 'name' } 9 } 10 }, { 11 '$project': { 12 'score': { '$meta': 'searchScore' }, '_id': 0, 'number_of_employees': 1, 'founded_year': 1, 'name': 1 13 } 14 }, { 15 '$set': { 'source': 'companies' } 16 }, { 17 '$limit': 3 18 }, { 19 '$unionWith': { 20 'coll': 'inspections', 21 'pipeline': [ 22 { 23 '$search': { 24 'text': { 'query': 'Mobile', 'path': 'business_name' } 25 } 26 }, { 27 '$set': { 'source': 'inspections' } 28 }, { 29 '$project': { 30 'score': { '$meta': 'searchScore' }, 'source': 1, '_id': 0, 'business_name': 1, 'address': 1 31 } 32 }, { 33 '$limit': 3 34 }, { 35 '$sort': { 'score': -1 } 36 } 37 ] 38 } 39 } 40 ]) 41 42 for i in result: 43 print(i)
This query uses the following stages:
$search
to search for companies that includemobile
in the name.$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$addFields
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A field name
source_count
that shows a count of the output documents.
$unionWith
to do the following:Use
$search
stage in the sub-pipeline to search for inspections of companies that includemobile
in the name.Perform a union of documents from the
companies
and documents from theinspections
collections.
$project
stage to:Include only the specified fields in the results.
Add a field named
score
.
$limit
stage to limit the output to3
results from each collection.$set
stage to add the following new fields:A new field named
source
that identifies the collection of the output documents.A new field named
source_count
that shows a count of the output documents.
1 import pymongo 2 import dns 3 4 client = pymongo.MongoClient('<connection-string>') 5 result = client['sample_training']['companies'].aggregate([ 6 {'$search': { 'text': { 7 'query': 'mobile', 8 'path': 'name', 9 'score': { 'boost': { 'value': 1.6 } } 10 }}}, 11 {'$project': { 12 'score': { '$meta': 'searchScore' }, 13 '_id': 0, 14 'number_of_employees': 1, 15 'founded_year': 1, 16 'name': 1 17 }}, 18 {'$addFields': { 19 'source': 'companies', 20 'source_count': '$$SEARCH_META.count.lowerBound' 21 }}, 22 {'$limit': 3}, 23 {'$unionWith': { 24 'coll': 'inspections', 25 'pipeline': [ 26 {'$search': { 'text': { 27 'query': 'mobile', 28 'path': 'business_name' 29 }} }, 30 {'$project': { 31 'score': { '$meta': 'searchScore' }, 32 'business_name': 1, 33 'address': 1, 34 '_id': 0 35 }}, 36 {'$limit': 3}, 37 {'$set': { 38 'source': 'inspections', 39 'source_count': '$$SEARCH_META.count.lowerBound' 40 }}, 41 {'$sort': { 'score': -1 }} 42 ] 43 }}, 44 {'$facet': { 45 'allDocs': [], 46 'totalCount': [ 47 {'$group': { 48 '_id': '$source', 49 'firstCount': { '$first': '$source_count' } 50 }}, 51 {'$project': { 52 'totalCount': { '$sum': '$firstCount' } 53 }} 54 ] 55 }} 56 ]) 57 58 for i in result: 59 print(i)
Replace the <connection-string>
in the query and then save the file.
Ensure that your connection string includes your database user's credentials. To learn more, see Connect via Drivers.
Run the command to query your collection.
python search-with-unionwith-query.py
{'name': 'XLR8 Mobile', 'number_of_employees': 21, 'founded_year': 2006, 'score': 2.0815043449401855, 'source': 'companies'} {'name': 'Pulse Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 2.0815043449401855, 'source': 'companies'} {'name': 'T-Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 2.0815043449401855, 'source': 'companies'} {'business_name': 'T. MOBILE', 'address': {'city': 'BROOKLYN', 'zip': 11209, 'street': '86TH ST', 'number': 440}, 'source': 'inspections', 'score': 2.900916337966919} {'business_name': 'BOOST MOBILE', 'address': {'city': 'BRONX', 'zip': 10458, 'street': 'E FORDHAM RD', 'number': 261}, 'source': 'inspections', 'score': 2.900916337966919} {'business_name': 'SPRING MOBILE', 'address': {'city': 'SOUTH RICHMOND HILL', 'zip': 11419, 'street': 'LIBERTY AVE', 'number': 12207}, 'source': 'inspections', 'score': 2.900916337966919}
python search-with-unionwith-query.py
{ 'allDocs': [ {'name': 'XLR8 Mobile', 'number_of_employees': 21, 'founded_year': 2006, 'score': 3.33040714263916, 'source': 'companies', 'source_count': 52}, {'name': 'Pulse Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 3.33040714263916, 'source': 'companies', 'source_count': 52}, {'name': 'T-Mobile', 'number_of_employees': None, 'founded_year': None, 'score': 3.33040714263916, 'source': 'companies', 'source_count': 52}, {'business_name': 'T. MOBILE', 'address': {'city': 'BROOKLYN', 'zip': 11209, 'street': '86TH ST', 'number': 440}, 'score': 2.900916337966919, 'source': 'inspections', 'source_count': 456}, {'business_name': 'BOOST MOBILE', 'address': {'city': 'BRONX', 'zip': 10458, 'street': 'E FORDHAM RD', 'number': 261}, 'score': 2.900916337966919, 'source': 'inspections', 'source_count': 456}, {'business_name': 'SPRING MOBILE', 'address': {'city': 'SOUTH RICHMOND HILL', 'zip': 11419, 'street': 'LIBERTY AVE', 'number': 12207}, 'score': 2.900916337966919, 'source': 'inspections', 'source_count': 456} ], 'totalCount': [ {'_id': 'companies', 'totalCount': 52}, {'_id': 'inspections', 'totalCount': 456} ] }
Run Atlas Search Queries Using Materialized Views
This tutorial describes how to create an index and run queries against
the sample_supplies.sales
collection from the sample dataset and a new sample_supplies.purchaseOrders
.
An on-demand materialized view is a collection that you create and
update using a $merge
aggregation pipeline stage. You can create an
Atlas Search index on the materialized view and then run queries on the
materialized view using the $search
aggregation pipeline stage.
This tutorial takes you through the following steps:
Create a collection named
purchaseOrders
in thesample_supplies
database.Create two scheduled triggers:
updateMonthlySales
, with a function namedupdateMonthlySales
that initializes themonthlyPhoneTransactions
materialized view using data from the samplesample_supplies.sales
collection.updateMonthlyPurchaseOrders
, with a function namedupdateMonthlyPurchaseOrders
that updates themonthlyPhoneTransactions
materialized view using data from thesample_supplies.purchaseOrders
collection.
Create an Atlas Search index on the
monthlyPhoneTransactions
materialized view.Run a query on the
monthlyPhoneTransactions
materialized view.
Create the purchaseOrders
Collection
Connect to the sample_supplies
database.
Open
mongosh
in a terminal window and connect to your cluster. For detailed instructions on connecting, see Connect viamongosh
.Use the
sample_supplies
database:use sample_supplies
Add a new collection.
Add the purchaseOrders
collection with new phone purchase
order data from January of 2018. Run the following commands:
db.purchaseOrders.insertMany( [ { saleDate: ISODate("2018-01-23T21:06:49.506Z"), items: [ { name: 'printer paper', tags: [ 'office', 'stationary' ], price: Decimal128("40.01"), quantity: 2 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("35.29"), quantity: 2 }, { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ], price: Decimal128("56.12"), quantity: 5 }, { name: 'backpack', tags: [ 'school', 'travel', 'kids' ], price: Decimal128("77.71"), quantity: 2 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("18.47"), quantity: 2 }, { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("19.95"), quantity: 8 }, { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("8.08"), quantity: 3 }, { name: 'binder', tags: [ 'school', 'general', 'organization' ], price: Decimal128("14.16"), quantity: 3 } ], storeLocation: 'Denver', customer: { gender: 'M', age: 42, email: 'cauho@witwuta.sv', satisfaction: 4 }, couponUsed: true, purchaseMethod: 'Phone' } ])
db.purchaseOrders.insertMany( [ { saleDate: ISODate("2018-01-25T10:01:02.918Z"), items: [ { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("8.05"), quantity: 10 }, { name: 'binder', tags: [ 'school', 'general', 'organization' ], price: Decimal128("28.31"), quantity: 9 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("20.95"), quantity: 3 }, { name: 'laptop', tags: [ 'electronics', 'school', 'office' ], price: Decimal128("866.5"), quantity: 4 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("33.09"), quantity: 4 }, { name: 'printer paper', tags: [ 'office', 'stationary' ], price: Decimal128("37.55"), quantity: 1 }, { name: 'backpack', tags: [ 'school', 'travel', 'kids' ], price: Decimal128("83.28"), quantity: 2 }, { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ], price: Decimal128("42.9"), quantity: 4 }, { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("16.68"), quantity: 2 } ], storeLocation: 'Seattle', customer: { gender: 'M', age: 50, email: 'keecade@hem.uy', satisfaction: 5 }, couponUsed: false, purchaseMethod: 'Phone' } ])
Query the new collection.
Query the purchaseOrders
collection to confirm the new
purchase order entries.
db.purchaseOrders.find().sort( {saleDate: -1} )
{ _id: ObjectId("62434c07d574cd0ce200ba75"), saleDate: ISODate("2018-01-25T10:01:02.918Z"), items: [ { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("8.05"), quantity: 10 }, { name: 'binder', tags: [ 'school', 'general', 'organization' ], price: Decimal128("28.31"), quantity: 9 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("20.95"), quantity: 3 }, { name: 'laptop', tags: [ 'electronics', 'school', 'office' ], price: Decimal128("866.5"), quantity: 4 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("33.09"), quantity: 4 }, { name: 'printer paper', tags: [ 'office', 'stationary' ], price: Decimal128("37.55"), quantity: 1 }, { name: 'backpack', tags: [ 'school', 'travel', 'kids' ], price: Decimal128("83.28"), quantity: 2 }, { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ], price: Decimal128("42.9"), quantity: 4 }, { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("16.68"), quantity: 2 } ], storeLocation: 'Seattle', customer: { gender: 'M', age: 50, email: 'keecade@hem.uy', satisfaction: 5 }, couponUsed: false, purchaseMethod: 'Phone' }, { _id: ObjectId("62434c07d574cd0ce200ba74"), saleDate: ISODate("2018-01-23T21:06:49.506Z"), items: [ { name: 'printer paper', tags: [ 'office', 'stationary' ], price: Decimal128("40.01"), quantity: 2 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("35.29"), quantity: 2 }, { name: 'pens', tags: [ 'writing', 'office', 'school', 'stationary' ], price: Decimal128("56.12"), quantity: 5 }, { name: 'backpack', tags: [ 'school', 'travel', 'kids' ], price: Decimal128("77.71"), quantity: 2 }, { name: 'notepad', tags: [ 'office', 'writing', 'school' ], price: Decimal128("18.47"), quantity: 2 }, { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("19.95"), quantity: 8 }, { name: 'envelopes', tags: [ 'stationary', 'office', 'general' ], price: Decimal128("8.08"), quantity: 3 }, { name: 'binder', tags: [ 'school', 'general', 'organization' ], price: Decimal128("14.16"), quantity: 3 } ], storeLocation: 'Denver', customer: { gender: 'M', age: 42, email: 'cauho@witwuta.sv', satisfaction: 4 }, couponUsed: true, purchaseMethod: 'Phone' }
The two query results reflect that the purchase order data ends in January of 2018.
Create the Scheduled Triggers
Note
To create the triggers, you must have Project Owner
or higher access
to the project.
In the following procedures, you create triggers to create a materialized view and schedule a function to update the materialized view daily. Expand the following sections to view the steps for each trigger:
In Atlas, go to the Triggers page for your project.
Warning
Navigation Improvements In Progress
We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.
If it's not already displayed, select the organization that contains your project from the Organizations menu in the navigation bar.
If it's not already displayed, select your project from the Projects menu in the navigation bar.
In the sidebar, click Triggers under the Services heading.
The Triggers page displays.
Enter configuration values for the Trigger.
UI Field Name | Configuration |
---|---|
Trigger Type | Select Scheduled. |
Name | Specify |
Schedule Type |
|
Select An Event Type | Select Function. |
Create the Function.
The function for this trigger defines a
monthlyPhoneTransactions
materialized view that contains cumulative
monthly sales information. The function updates monthly sales
information for sales conducted over the phone.
Paste the following code into the function:
exports = function(){ var pipeline = [ { $match: {purchaseMethod: "Phone"} }, { $unwind: {path: "$items"}}, { $group: { _id: { $dateToString: { format: "%Y-%m", date: "$saleDate" } }, sales_quantity: { $sum: "$items.quantity"}, sales_price: { $sum: "$items.price"} }}, { $set: { sales_price: { $toDouble: "$sales_price"}}}, { $merge: { into: "monthlyPhoneTransactions", whenMatched: "replace" } } ] var monthlyPhoneTransactions = context.services.get("mongodb-atlas").db("sample_supplies").collection("sales"); return monthlyPhoneTransactions.aggregate(pipeline); };
The function uses the following aggregation pipeline stages to update
monthlyPhoneTransactions
:
The
$match
stage filters the data to process only those sales that were completed over thePhone
.The
$group
stage groups the sales information by the year-month. This stage outputs documents of the form:{ "_id" : "<YYYY-mm>", "sales_quantity" : <num>, "sales_amount" : <NumberDecimal> } The
$set
stage changes the data type of thesales_price
field todouble
. Atlas Search$search
operators don't support theDecimal128
data type. Changing thesales_price
field's data type allows you to query this field using Atlas Search indexes.The
$merge
stage writes the output to themonthlyPhoneTransactions
collection.Based on the
_id
field, the stage checks if the document in the aggregation results matches an existing document in the collection:When Atlas Search finds a match (that is, a document with the same year-month already exists in the collection), Atlas Search replaces the existing document with the document from the aggregation results as specified in the stage.
When Atlas Search doesn't find a match, Atlas Search inserts the document from the aggregation results into the collection as specified in the stage.
In Atlas, go to the Triggers page for your project.
Warning
Navigation Improvements In Progress
We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.
If it's not already displayed, select the organization that contains your project from the Organizations menu in the navigation bar.
If it's not already displayed, select your project from the Projects menu in the navigation bar.
In the sidebar, click Triggers under the Services heading.
The Triggers page displays.
Enter configuration values for the Trigger.
UI Field Name | Configuration |
---|---|
Trigger Type | Select Scheduled. |
Name | Specify |
Schedule Type |
|
Create the Function.
How the updateMonthlyPurchaseOrders
Function Works
The updateMonthlyPurchaseOrders
function adds cumulative monthly
purchase order information to the monthlyPhoneTransactions
materialized view. The function updates the monthly purchase order
information for purchase orders conducted over the phone.
The following example defines the function:
exports = function(){ var pipeline = [ { $match: {purchaseMethod: "Phone"} }, { $unwind: {path: "$items"}}, { $group: { _id: { $dateToString: { format: "%Y-%m", date: "$saleDate" } }, sales_quantity: { $sum: "$items.quantity"}, sales_price: { $sum: "$items.price"} }}, { $set: { sales_price: { $toDouble: "$sales_price"}}}, { $merge: { into: "monthlyPhoneTransactions", whenMatched: "replace" } } ] var monthlyPhoneTransactions = context.services.get("mongodb-atlas").db("sample_supplies").collection("purchaseOrders"); return monthlyPhoneTransactions.aggregate(pipeline); };
The updateMonthlyPurchaseOrders
function uses the same aggregation
pipeline stages to update monthlyPhoneTransactions
as the
updateMonthlySales
function.
Test the Function.
Click the Run button in the
lower right-hand corner of the Function Editor
to update the monthlyPhoneTransactions
materialized view.
The Result tab at the bottom of the Function Editor reflects the execution status of the function.
The updateMonthlyPurchaseOrders
function refreshes the
monthlyPhoneTransactions
materialized view with the January
2018 purchase order data.
Use mongosh
to query the
monthlyPhoneTransactions
collection to confirm the update:
db.monthlyPhoneTransactions.find().sort( { _id: -1} )
{ _id: '2018-01', sales_quantity: 66, sales_price: Decimal128("1407.10") }
The monthlyPhoneTransactions
materialized view shows the
newly added data. The top result reflects that the most recent
transaction took place in January 2018.
Create an Atlas Search Index on the Materialized View
Create an Atlas Search index on the monthlyPhoneTransactions
collection.
In Atlas, go to the Clusters page for your project.
Warning
Navigation Improvements In Progress
We're currently rolling out a new and improved navigation experience. If the following steps don't match your view in the Atlas UI, see the preview documentation.
If it's not already displayed, select the organization that contains your desired project from the Organizations menu in the navigation bar.
If it's not already displayed, select your desired project from the Projects menu in the navigation bar.
If it's not already displayed, click Clusters in the sidebar.
The Clusters page displays.
Start your index configuration.
Make the following selections on the page and then click Next.
Search Type | Select the Atlas Search index type. |
Index Name and Data Source | Specify the following information:
|
Configuration Method | For a guided experience, select Visual Editor. To edit the raw index definition, select JSON Editor. |
Note
Your Atlas Search index is named default
by default. If you keep this name, then your index will be the
default Search index for any Atlas Search query that does not specify a different index
option in
its operators. If you are creating multiple indexes, we recommend
that you maintain a consistent, descriptive naming convention across your indexes.
Check the status.
The newly created index appears on the Atlas Search tab. While the index is building, the Status field reads Building. When the index is finished building, the Status field reads Active.
Note
Larger collections take longer to index. You will receive an email notification when your index is finished building.
Run a Query on the Materialized View
Run a query against the newly updated and indexed
monthlyPhoneTransactions
collection.
Connect to your cluster in mongosh
.
Open mongosh
in a terminal window and
connect to your cluster. For detailed instructions on connecting,
see Connect via mongosh
.
Use the sample_supplies
database.
Run the following command at mongosh
prompt:
use sample_supplies
Run a simple Atlas Search query on the sample_supplies.monthlyPhoneTransactions
collection.
The following query counts the number of months in monthlyPhoneTransactions
with total sales greater than or equal to 10000
dollars:
db.monthlyPhoneTransactions.aggregate([ { $search: { "index": "monthlySalesIndex", "range": { "gt": 10000, "path": ["sales_price"] } } }, { $count: 'months_w_over_10000' }, ])
The above query returns 4
,
indicating that only 4 months out of all the months in the
monthlyPhoneTransactions
materialized view had total sales
greater than or equal to 10000 dollars. This result reflects data
from both the sample_supplies.sales
and
sample_supplies.purchaseOrders
collections.
For complete aggregation pipeline documentation, see the MongoDB Server Manual.