2
votes

I have an Azure CosmosDb database with database-level throughput provisioned. We're using the MongoDB API against this Cosmos instance. The shared throughput model requires all collections to have a partition key specified, which seems to prevent pretty much any tools from being able to create a collection, other than the Azure Portal or the official Azure Cosmos SDKs. For example, in Robo 3T, attempting to create a collection results in the following error:

Failed to create collection 'mycollection'.

Error: Shared throughput collection should have a partition key

The same error occurs when attempting to create a collection via mongoose (similar to this question) or other tooling.

So I guess the operative question boils down to this: Is there any way through the MongoDb API to pass the desired partitionKey to CosmosDb, so that collection creation will succeed?

2

2 Answers

1
votes

Use the shardCollection command via db.runCommand(...)

It turns out there is a working, if obscure, way to achieve this with the MongoDb wire protocol. You can create a collection with a Cosmos partition key (which conceptually maps to the Mongo Shard Key), by issuing a db-level command to set the sharding key for the not-yet-existing collection:

In a mongo shell:

db.runCommand({shardCollection: "myDbName.nameOfCollectionToCreate", 
               key: {nameOfDesiredPartitionKey: "hashed"}})

After running this, my ComosDb database (with database-level shared throughput) now contains the new collection with the partition key set appropriately!

I haven't figured out a way to call runCommand directly via Mongoose yet, but at least this native/wire protocol approach should work with any of the official MongoDb drivers, so is far more portable than depending on the Azure Cosmos SDK just to create a collection.

1
votes

Extension commands could be used.

Create collection

The format of the CreateCollection command is as follows:

{
  customAction: "CreateCollection",
  collection: "<Collection Name>",
  shardKey: "<Shard key path>",
  offerThroughput: (int), // Amount of throughput allocated to a specific collection
}

JavaScript

db.runCommand({customAction: "CreateCollection", collection: "testCollection", shardKey: "sharedKeyName"});

Java

BasicDBObject testCollection = new BasicDBObject("customAction", "CreateCollection")
                            .append("collection", "testCollection")
                            .append("shardKey", "sharedKeyName");
db.runCommand(testCollection);