Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8e478ef

Browse files
committed
Add transaction
Add script to create new users Working transaction Add abort transaction Added logging and doc Add docs Add unique index Formatting and typos Update sample user names Add session to findOne()
1 parent 7f3cead commit 8e478ef

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed

‎transaction.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
const { MongoClient } = require('mongodb');
2+
3+
// CRUD operations in transactions must be on existing collections, so be sure you have run
4+
// usersCollection.js prior to running this script.
5+
6+
async function main() {
7+
/**
8+
* Connection URI. Update <username>, <password>, and <your-cluster-url> to reflect your cluster.
9+
* See http://bit.ly/NodeDocs_lauren for more details
10+
*/
11+
const uri = "mongodb+srv://<username>:<password>@<your-cluster-url>/test?retryWrites=true&w=majority";
12+
13+
/**
14+
* The Mongo Client you will use to interact with your database
15+
* See bit.ly/Node_MongoClient for more details
16+
*/
17+
const client = new MongoClient(uri);
18+
19+
try {
20+
// Connect to the MongoDB cluster
21+
await client.connect();
22+
23+
// Make the appropriate DB calls
24+
25+
await createReservation(client,
26+
"leslie@example.com",
27+
"Infinite Views",
28+
[new Date("2019年12月31日"), new Date("2020年01月01日")],
29+
{ pricePerNight: 180, specialRequests: "Late checkout", breakfastIncluded: true });
30+
31+
} finally {
32+
// Close the connection to the MongoDB cluster
33+
await client.close();
34+
}
35+
}
36+
37+
main().catch(console.error);
38+
39+
/**
40+
* Create a reservation by storing information in both the users collection and the listingsAndReviews collection
41+
* Note: this function assumes there is only one Airbnb listing in the collection with the given name. If more than
42+
* listing exists with the given name, a reservation will be created for the first listing the database finds.
43+
* @param {MongoClient} client A MongoClient that is connected to a cluster with the sample_airbnb database
44+
* @param {String} userEmail The email address of the user who is creating the reservation
45+
* @param {String} nameOfListing The name of the Airbnb listing to be reserved
46+
* @param {Array.Date} reservationDates An array of the date(s) for the reservation
47+
* @param {Object} reservationDetails An object containing additional reservation details that need to be stored with the reservation
48+
*/
49+
async function createReservation(client, userEmail, nameOfListing, reservationDates, reservationDetails) {
50+
51+
/**
52+
* The users collection in the sample_airbnb database
53+
*/
54+
const usersCollection = client.db("sample_airbnb").collection("users");
55+
56+
/**
57+
* The listingsAndReviews collection in the sample_airbnb database
58+
*/
59+
const listingsAndReviewsCollection = client.db("sample_airbnb").collection("listingsAndReviews");
60+
61+
/**
62+
* The reservation document that will be added to the users collection document for this user
63+
*/
64+
const reservation = createReservationDocument(nameOfListing, reservationDates, reservationDetails);
65+
66+
// Step 1: Start a Client Session
67+
// See http://bit.ly/Node_startSession for the startSession() docs
68+
const session = client.startSession();
69+
70+
// Step 2: Optional. Define options to use for the transaction
71+
const transactionOptions = {
72+
readPreference: 'primary',
73+
readConcern: { level: 'local' },
74+
writeConcern: { w: 'majority' }
75+
};
76+
77+
try {
78+
// Step 3: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error)
79+
// Note: The callback for withTransaction MUST be async and/or return a Promise.
80+
// See http://bit.ly/Node_withTransaction for the withTransaction() docs
81+
const transactionResults = await session.withTransaction(async () => {
82+
83+
// Important:: You must pass the session to each of the operations
84+
85+
// Add a reservation to the reservations array for the appropriate document in the users collection
86+
const usersUpdateResults = await usersCollection.updateOne(
87+
{ email: userEmail },
88+
{ $addToSet: { reservations: reservation } },
89+
{ session });
90+
console.log(`${usersUpdateResults.matchedCount} document(s) found in the users collection with the email address ${userEmail}.`)
91+
console.log(`${usersUpdateResults.modifiedCount} document(s) was/were updated to include the reservation.`);
92+
93+
// Check if the Airbnb listing is already reserved for those dates. If so, abort the transaction.
94+
const isListingReservedResults = await listingsAndReviewsCollection.findOne(
95+
{ name: nameOfListing, datesReserved: { $in: reservationDates } },
96+
{ session });
97+
if (isListingReservedResults) {
98+
await session.abortTransaction();
99+
console.error("This listing is already reserved for at least one of the given dates. The reservation could not be created.");
100+
console.error("Any operations that already occurred as part of this transaction will be rolled back.")
101+
return;
102+
}
103+
104+
// Add the reservation dates to the datesReserved array for the appropriate document in the listingsAndRewiews collection
105+
const listingsAndReviewsUpdateResults = await listingsAndReviewsCollection.updateOne(
106+
{ name: nameOfListing },
107+
{ $addToSet: { datesReserved: { $each: reservationDates } } },
108+
{ session });
109+
console.log(`${listingsAndReviewsUpdateResults.matchedCount} document(s) found in the listingsAndReviews collection with the name ${nameOfListing}.`)
110+
console.log(`${listingsAndReviewsUpdateResults.modifiedCount} document(s) was/were updated to include the reservation dates.`);
111+
112+
}, transactionOptions);
113+
114+
// TODO: I couldn't find documentation that explicitly said that the transactionResults will be undefined if the transaction is
115+
// unsuccessful, but that seems to be the case. Can you confirm this is true?
116+
if (transactionResults) {
117+
console.log("The reservation was successfully created.");
118+
} else {
119+
console.log("An error occurred and the reservation could not be created.");
120+
}
121+
} finally {
122+
// Step 4: End the session
123+
await session.endSession();
124+
}
125+
126+
}
127+
128+
/**
129+
* A helper function that generates a reservation document
130+
* @param {String} nameOfListing The name of the Airbnb listing to be reserved
131+
* @param {Array.Date} reservationDates An array of the date(s) for the reservation
132+
* @param {Object} reservationDetails An object containing additional reservation details that need to be stored with the reservation
133+
* @returns {Object} The reservation document
134+
*/
135+
function createReservationDocument(nameOfListing, reservationDates, reservationDetails) {
136+
// Create the reservation
137+
let reservation = {
138+
name: nameOfListing,
139+
dates: reservationDates,
140+
}
141+
142+
// Add additional properties from reservationDetails to the reservation
143+
for (let detail in reservationDetails) {
144+
reservation[detail] = reservationDetails[detail];
145+
}
146+
147+
return reservation;
148+
}

‎usersCollection.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const { MongoClient } = require('mongodb');
2+
3+
/**
4+
* This script creates 3 new users in the users collection in the sample_airbnb database.
5+
* The users collection does not need to exist before running this script.
6+
* This script also creates a unique index on the email field in the users collection.
7+
*
8+
* You will see "duplicate key" errors if you attempt to run this script more than once
9+
* without dropping the documents in the users collection, because the unique index will
10+
* not allow you to insert more than one document into the collection with the same email address.
11+
*/
12+
13+
async function main() {
14+
/**
15+
* Connection URI. Update <username>, <password>, and <your-cluster-url> to reflect your cluster.
16+
* See http://bit.ly/NodeDocs_lauren for more details
17+
*/
18+
const uri = "mongodb+srv://<username>:<password>@<your-cluster-url>/test?retryWrites=true&w=majority";
19+
20+
/**
21+
* The Mongo Client you will use to interact with your database
22+
* See bit.ly/Node_MongoClient for more details
23+
*/
24+
const client = new MongoClient(uri);
25+
26+
try {
27+
// Connect to the MongoDB cluster
28+
await client.connect();
29+
30+
// Make the appropriate DB calls
31+
32+
// Create 3 new users in the users collection
33+
await createMultipleUsers(client, [
34+
{
35+
email: "leslie@example.com",
36+
name: "Leslie Yepp"
37+
},
38+
{
39+
email: "april@example.com",
40+
name: "April Ludfence"
41+
},
42+
{
43+
email: "tom@example.com",
44+
name: "Tom Haverdodge"
45+
}
46+
]);
47+
48+
// Create a unique index on the email field in the users collection.
49+
// Note that if you run this script when you already have duplicate emails in the user collection,
50+
// MongoDB will be unable to create the unique index.
51+
const createIndexResults = await client.db("sample_airbnb").collection("users").createIndex({ "email": 1 }, { unique: true });
52+
console.log(`Index successfully created: ${createIndexResults}`);
53+
54+
} finally {
55+
// Close the connection to the MongoDB cluster
56+
await client.close();
57+
}
58+
}
59+
60+
main().catch(console.error);
61+
62+
/**
63+
* Create multiple users
64+
* @param {MongoClient} client A MongoClient that is connected to a cluster with the sample_airbnb database
65+
* @param {Object[]} newUsers The new users to be added
66+
*/
67+
async function createMultipleUsers(client, newUsers) {
68+
// See http://bit.ly/Node_InsertMany for the insertMany() docs
69+
const result = await client.db("sample_airbnb").collection("users").insertMany(newUsers);
70+
71+
console.log(`${result.insertedCount} new user(s) created with the following id(s):`);
72+
console.log(result.insertedIds);
73+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /