Using a batch to create a collection and a subcollection at once - javascript

I'm trying to create a new collection, and then create a sub collection all at once.
The code is being run when a user creates a new team and adds a players to the team. (both team and player are created/added at the same time)
This is what I have attempted so far:
const batch = db.batch()
const collectionRef = db.collection('users').doc(user.uid).collection('teams').doc(id)
batch.set(
collectionRef.set({
teamId: id,
teamName: teamName
})
)
batch.set(
collectionRef.collection('players').doc(player.id).set(playerObject)
)
batch.commit().then(()=> {}).catch(err=> console.log(err))
The player object is defined like so:
{
name: 'John Doe',
id: '123',
imgs: ['img.png']
...
}
But whenever this runs, only the first write is executed, the sub collection is not created. I think this is because the collection does not exist, so might cause an issue.

Using firestore Batch is a better approach to do this. Create a batch and add the main document followed by the subcollection document(s).A collection is created once a document is written to it, and removed automatically once the last document is removed from it.
If you want to write the collection [parent] and the subcollection [child] in a single batch write, you can do it by generating a UniqueID for the parent document, and then creating the sub collection documents under that same path for example as below:
Take a document document under the collection_name collection at the
path collection_name/document/
And another one sub-collection_name document under the
subCollection_name (sub-)collection
collection_name/document/subCollection_name/sub-collection dcoument
Also as mentioned above in the comments from Alex,use reference for the collection object while calling the object in the code to create the path for collection and sub-collection reference path, if the reference object and path is not defined the code will not work.
You may check the below examples for similar implementation:
How to add sub collection to firestore
Create document and sub-collection in one shot
Add collection and subcollection as batch writes

Related

Firebase - Create subcollection only if the parent doc exists

In Firestore, when you are deleting a doc, you can specify a condition like { exists: true }, in order to avoid deleting the document if it doesn't exist.
In a concurrent scenario, it is possible that we would only like to add a doc to a subcollection if the parent document exists.
For example, imagine the following NoSql structure:
-comment (doc)
/likes (subcollection created when the first like is given)
-like1
-like2
...
Is it possible to do something like
likeRef.create(data, { parent_exists: true });
??
Is the only way to handle this situation with Transactions (reading the parent doc, and throwing an error when .exists() is false)?
I am afraid of this type of situation because if the sub-collection is created at the same time as the container document is deleted, there could be orphan "entities" in the database that may even break the UI if it is not prepared for these extreme cases.
This is not possible as a single operation in Firestore.
The only way to do this is to start a transaction, then get() the parent document inside the transaction, and add the documents to the subcollection if the parent exists.

Need to write to collection in a collection in Firebase

I need to change my web app (JavaScript) I use to load products to Firebase Firestore to create a collection ('blue_bottle') in a collection ('promotions'). It use to write straight into a collection ('blue_bottle') which was sharp for time being. What do I have to add to make it write to a collection ('promotions') first, then to collection ('blue_bottle')
I can't seem to find very much JavaScript and Firebase reference.
form.addEventListener('submit', (e) => {
e.preventDefault();
db.collection('blue_bottle').add({
Obviously this was the first thing I tried without success:
form.addEventListener('submit', (e) => {
e.preventDefault();
db.collection('promotions').db.collection('blue_bottle').add({
Now it first need to go to a collection ('promotions') please.
Thank you
The Firestore content model is that a document can only exist in a collection, and a subcollection can only exist in a document. There is no way to nest a collection directly under a collection.
To add something under a nested collection under a document, the syntax is:
db.collection('promotions').doc('the parent document').collection('blue_bottle').add({
...
})
Or shorter:
db.collection('promotions/the parent document/blue_bottle').add({
...
})

Using firebase .update within a .where (instead of .doc)

I am new to firebase and am struggling a little bit.
Currently, I am trying to update an array within a user, within a document. However, I cannot match the user to current user using the unique ID, as each users unique ID is their username, and it may have changed since creation.
I figured the best way to match the documents user to the current user would be to use a .where().get() and then use an "update()" to update the array.
Now, this is where I am getting stuck. In the firebase documents, their example of using .update is attached to a .doc
var washingtonRef = db.collection("cities").doc("DC");
//Atomically add a new region to the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});
However, as I am using a .where, I assume I have to use references and snapshots. But, I am not quite sure how references work in this scenario and, with that, how to update properly.
Here is the code I have after a while of messing round, but no matter my variations i cannot figure it out. (essentially, I want to add a new project (in this case called "new project" to the users array of postedProjects.)
db.collection('users').where('user_id', '==', this.userInfo.user_id)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
doc.data().update({
postedProjects: firebase.firestore.FieldValue.arrayUnion("new project")
})
})
})
This gives me an error of ".update() is not a function".
Is anyone able to help me with my solution to show me how references should properly be used in this scenario?
You're almost there. You can't update the data of DocumentSnapshot though, since that is the in-memory representation of the document data. Instead you need to get the DocumentReference and call update on that.
doc.ref.update({
postedProjects: firebase.firestore.FieldValue.arrayUnion("new project")
})
You need a DocumentReference in order to update() a document. Nothing else will work.
In your code, doc is a QueryDocumentSnapshot type object. If you want the DocumentReference object that refers to the document from that snapshot, use its ref property.
doc.ref.update({
postedProjects: firebase.firestore.FieldValue.arrayUnion("new project")
})

Querying with Bookshelf

I recently started using Bookshelf. Examples in the documentation aren't very clear to me. This is one such example:
var knex = require('knex')({
client: 'mysql',
connection: process.env.MYSQL_DATABASE_CONNECTION
});
var bookshelf = require('bookshelf')(knex);
var User = bookshelf.Model.extend({
tableName: 'users',
posts: function() {
return this.hasMany(Posts);
}
});
var Posts = bookshelf.Model.extend({
tableName: 'messages',
tags: function() {
return this.belongsToMany(Tag);
}
});
var Tag = bookshelf.Model.extend({
tableName: 'tags'
})
User.where('id', 1).fetch({
withRelated: ['posts.tags']
}).then(function(user) {
console.log(user.related('posts').toJSON());
}).catch(function(err) {
console.error(err);
});
After the creation of three models (User, Posts, and Tag) - there is a query.
What exactly is the meaning of this query?
User.where('id', 1).fetch({withRelated: ['posts.tags']}).then(function(user) {
console.log(user.related('posts').toJSON());
}).catch(function(err) {
console.error(err);
});
What are withRelated, 'posts.tags', user.related('posts')? Can anyone tell me in simplest form, what those terms are and where they come from?
Finally, what is the meaning of the complete query?
It's all answered in the documentation, although not everything in the exact same place, so I can understand your confusion. You really have to read the whole thing to better understand it.
From the documentation of Model.fetch():
withRelated: Relations to be retrieved with Model instance. Either one or more relation names (...) A single property, or an array of properties can be specified as a value for the withRelated property.
From Collection.fetch():
The withRelated option may be specified to fetch the models of the collection, eager loading any specified relations named on the model.
From Collection.load():
... Nested eager loads can be specified by separating the nested relations with .
From Model.related():
The related method returns a specified relation loaded on the relations hash on the model, or calls the associated relation method and adds it to the relations hash if one exists and has not yet been loaded.
All of these are involved in the eager loading of relations on models.
What these methods do is load some data from a table that is related to the parent model's table in some way. In the example you posted, the User model has some Posts and the Posts themselves have some tags, so the relations go something like:
User
|_ Post
|_ Tag
These are expressed as methods on each model, for example, posts: function() { ... } in the User model.
When you specify a relation to eager load using withRelated, you use these method names. Furthermore you can eager load deeply nested relations by separating them with a ., and that's what you're seeing in the example.
So, putting everything together what that example is doing is searching for the User with id = 1 and also retrieving all the posts that belong to that user as well as all the tags that belong to all the posts that belong to the user.
Then to access these related objects you use the related('something') method of the model.

Create entity in Breeze relying on other entity

I'm working my way with BreezeJS in combination with Durandal. This all works fine but I have a question about creating a new entity that has a relation with another entity.
Lets say we have an entity customer and order. When I create a new order which relies on customer it has 2 fields one for customerID and one for Customer it self! The customerID is given correctly but it crashes for not having a Customer object! How do I solve this?
My Dataservice.createT is:
// This function creates an entity for the specific table (entity)
// that is passed as an parameter. The entity is the same as the table name
//in the map folders. So for creating a new Memo entity should be tblMemo
Dataservice.prototype.createT = function (initialValues, entity) {
return this.manager.createEntity(entity, initialValues);
};
var repairOrderLineN = dataservice.createT({
RepairOrderID: '1', CustomerID: result[0].CustomerId,
Description: result[0].Description, InternalCode: result[0].Code,
Hours: result[0].Hours, Tariff: result[0].Tariff,
Costs: result[0].Costs, Quantity: result[0].Qty,
DamageCode: result[0].Dam, RepairCode: result[0].Rep,
MaterialCode: result[0].Mat, LocationCode: result[0].Location,
IsAgreement: result[0].IsAgreement, IsAuthorized: result[0].IsAuthorized,
DoRepair: result[0].DoRepair
}, 'tblRepairOrderLine');
if (repairOrderLineN.entityAspect.validateEntity()) {
extendItem(repairOrderLineN);
repairorderlines.push(new repairorderline(repairOrderLineN));
dataservice.saveChanges();
updateFinance();
}
A JSON is given from a modal to create the entity and off course I understand the customer object isn't in it! damn i'm lost :S Help :(
I need more information about your case and specifically what you mean by "crashes".
I don't know what your dataservice.createT does. It's actually a little too complex for easy answer here. Can you simplify a test case for us?
Meanwhile, here is a passing test that I'm adding to "entityTests.js" of the DocCode sample that demonstrates your scenario with Northwind.
/*********************************************************
* Add an Order with initializer that set its parent Customer by Id
*********************************************************/
test("add Customer created using initializer with parent Customer Id", 4, function () {
var em = newEm();
// create a new parent Customer
var parentCustomer = em.createEntity("Customer", {
CustomerID: breeze.core.getUuid(),
CompanyName: 'TestCo'
});
// a new Order which is a child of the parent Customer
var newOrder = em.createEntity("Order", { CustomerID: parentCustomer.CustomerID() });
ok(newOrder.entityAspect.entityState.isAdded(), "newOrder should be 'added'");
ok(parentCustomer.entityAspect.entityState.isAdded(), "parentCustomer should be 'added'");
var orderCustomer = newOrder.Customer();
ok(orderCustomer, "newOrder's parent 'Customer' property should return a Customer entity");
ok(orderCustomer === parentCustomer,
"newOrder's parent Customer should be " + parentCustomer.CompanyName());
});
It would work just as well if the parent Customer previously existed (e.g., had been fetched).
Btw, I had to initialize parentCustomer.CustomerID because it is defined in metadata as a client-generated key. In most of our examples, the entity key is store-generated (e.g., Order.OrderID) and would not be specified.
Update 4/30/2013
I suspect that somewhere in your initializer object is a result[0].something where something is an entity rather than a simple data value (e.g,. an integer id).
As I write, the createEntity blows up if any initializer value is a Breeze entity. That will be fixed in v.1.3.2 which should be out soon. Note that this new feature will be beta at first. The API won't change but there are many edge conditions and it's hard to cover them all. It will take time to drive out lingering bugs.
No matter what, you have alternatives today. You would be fine if you just initialized using the foreign key ids for the related entities instead of initializing with the related entities themselves. Or you could assign the related entities after first creating the entity as in:
...
var thing = manager.createEntity('Thing', {
... initialize with simple data values
}
var thing.relatedEntityA = relatedEntityA;
var thing.relatedEntityB = relatedEntityB;
...

Categories

Resources