how to delete by value in angular 6 and firebase realtime database - firebase-realtime-database

Suppose I have a query in Mysql i.e.: " delete from table where counter= 3 "
what will be the query in angular 6 and firebase realtime database?
Thanks!!

deleteUser(count){
return this.db.collection('users',ref => ref.where('count', '=', count)).delete();
}
You can get the collection and delete its entity doc using key/id.

Related

How to structure data in Firestore using swift [duplicate]

The documentation does not have any examples on how to add a subcollection to a document. I know how to add document to a collection and how to add data to a document, but how do I add a collection (subcollection) to a document?
Shouldn't there be some method like this:
dbRef.document("example").addCollection("subCollection")
Edit 13 Jan 2021:
According to the updated documentation regarding array membership, now it is possible to filter data based on array values using whereArrayContains() method. A simple example would be:
CollectionReference citiesRef = db.collection("cities");
citiesRef.whereArrayContains("regions", "west_coast");
This query returns every city document where the regions field is an array that contains west_coast. If the array has multiple instances of the value you query on, the document is included in the results only once.
Assuming we have a chat application that has a database structure that looks similar to this:
To write a subCollection in a document, please use the following code:
DocumentReference messageRef = db
.collection("rooms").document("roomA")
.collection("messages").document("message1");
Creating a messages collection and calling addDocument() 1000 times will be expensive for sure, but this is how Firestore works. You can switch to Firebase Realtime Database if you want where the number of writes doesn't matter. But regarding Supported Data Types in Firestore, in fact, you can use an array because it is supported. In Firebase Realtime database you could also use an array, but this is an anti-pattern. One of the many reasons Firebase recommends against using arrays is that it makes the security rules impossible to write.
Cloud Firestore can store arrays, but it does not support querying array members or updating single array elements. However, you can still model this kind of data by leveraging the other capabilities of the Cloud Firestore. Here is the documentation where it is very well explained.
You also cannot create a subcollection with 1000 messages, add all of them to the database, and expect it to be considered a single record. It will be considered one write operation for every message, in total 1000 operations. The picture above does not show how to retrieve data, it shows a database structure in which you have something like this:
collection -> document -> subCollection -> document
Here's a variation where the subcollection is storing ID values at the collection level, rather than within a document where the subcollection is a field there with additional data.
This is useful for connecting a 1-to-Many ID mapping w/out having to drill through an additional document:
function fireAddStudentToClassroom(studentUserId, classroomId) {
var db = firebase.firestore();
var studentsClassroomRef =
db.collection('student_class').doc(classroomId)
.collection('students');
studentsClassroomRef
.doc(studentUserId)
.set({})
.then(function () {
console.log('Document Added ');
})
.catch(function (error) {
console.error('Error adding document: ', error);
});
}
Thanks to #Alex's answer
This answer a bit off from the original question here, where it explicitly asks for adding a collection to a document. However, after searching for a solution for this scenario and not finding any mention in docs or on SO, this post seems like a reasonable place to share the findings
Here's my code:
firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).set(wordData)
.then(function() {
console.log("Collection added to Firestore!");
var promises = [];
promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('AudioSources').doc($scope.accentDialect).set(accentDialectObject));
promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('FunFacts').doc($scope.longLanguage).set(funFactObject));
promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('Translations').doc($scope.translationLongLanguage).set(translationObject));
Promise.all(promises).then(function() {
console.log("All subcollections were added!");
})
.catch(function(error){
console.log("Error adding subcollections to Firestore: " + error);
});
})
.catch(function(error){
console.log("Error adding document to Firestore: " + error);
});
This makes a collection EnglishWords, which has a document of. The document of has three subcollections: AudioSources (recordings of the word in American and British accents), FunFacts, and Translations. The subcollection Translations has one document: Spanish. The Spanish document has three key-value pairs, telling you that 'de' is the Spanish translation of 'of'.
The first line of the code creates the collection EnglishWords. We wait for the promise to resolve with .then, and then we create the three subcollections. Promise.all tells us when all three subcollections are set.
IMHO, I use arrays in Firestore when the entire array is uploaded and downloaded together, i.e., I don't need to access individual elements. For example, an array of the letters of the word 'of' would be ['o', 'f']. The user can ask, "How do I spell 'of'?" The user isn't going to ask, "What's the second letter in 'of'?"
I use collections when I need to access individual elements, a.k.a. documents. With the older Firebase Realtime Database, I had to download arrays and then iterate through the arrays with forEach to get the element I wanted. This was a lot of code, and with a deep data structure and/or large arrays I was downloading tons of data that I didn't need, and slowing my app running forEach loops on large arrays. Firestore puts the iterators in the database, on their end, so that I can request a single element and it sends me just that element, saving me bandwidth and making my app run faster. This might not matter for a web app, if your computer has a broadband connection, but for mobile apps with poor data connections and slow devices this is important.
Here are two pictures of my Firestore:
From the docs:
You do not need to "create" or "delete" collections. After you create the first document in a collection, the collection exists. If you delete all of the documents in a collection, it no longer exists.
Here i faced the same issue and solve with the answere of #Thomas David Kehoe
db.collection("First collection Name").doc("Id of the document").collection("Nested collection Name").add({
//your data
}).then((data) => {
console.log(data.id);
console.log("Document has added")
}).catch((err) => {
console.log(err)
})
too late for an answer but here is what worked for me,
mFirebaseDatabaseReference?.collection("conversations")?.add(Conversation("User1"))
?.addOnSuccessListener { documentReference ->
Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.id)
mFirebaseDatabaseReference?.collection("conversations")?.document(documentReference.id)?.collection("messages")?.add(Message(edtMessage?.text.toString()))
}?.addOnFailureListener { e ->
Log.w(TAG, "Error adding document", e)
}
add success listener for adding document and use firebase generated ID for a path.
Use this ID for the complete path for a new collection you want to add.
I.E. - dbReference.collection('yourCollectionName').document(firebaseGeneratedID).collection('yourCollectionName').add(yourDocumentPOJO/Object)
Okay so I recently faced a similar problem given the recent update in the firebase/firestore documentation.
And here is a solution that worked for me
const sendMessage = async () => {
await setDoc(doc(db, COLLECTION_NAME, projectId, SUB_COLLECTION_NAME, nanoid()), {
text:'this is a sample text',
createdAt: serverTimestamp(),
name: currentUser?.firstName + ' ' + currentUser?.lastName,
photoUrl: currentUser?.photoUrl,
userId: currentUser?.id,
});
}
You can find a similar example in the docs
https://firebase.google.com/docs/firestore/data-model#web-version-9_3
chat room
If you wish to listen for live update you can use a similar method as follows
const messagesRef = collection(db, COLLECTION_NAME, projectId, SUB_COLLECTION_NAME)
const liveUpdate = async () => {
const queryObj = query(messagesRef, orderBy("createdAt"), limit(25));
onSnapshot(queryObj, (querySnapshot) => {
const msgArr: any = [];
querySnapshot.forEach((doc) => {
msgArr.push({ id: doc.id, ...doc.data() })
});
console.log(msgArr);
});
}
There is no separate method to add sub-collection into the document.
You can just call the collection method itself.
If the collection exists it will reference that otherwise create a new one.
dbRef.document("example").collection("subCollection")

How to access data in sql request

I'm runing a sql request in a model to get some data in relation.
I got a array called newScoring with ["_646_maturity", "_660_maturity", "_651_maturity", "_652_maturity", "_641_maturity"]
newScoring.each do |e|
numero = e.from(1).to(-10) // remove text to get only number : 646
sql = "SELECT * FROM pratiques WHERE numero LIKE '%"+numero+"%'" // sql request to get a pratique with numero equal to my previous number
records_array = ActiveRecord::Base.connection.execute(sql)
Rails.logger.debug "SQL : "+records_array
end
When I log records_array.inspect, I got
[{"id"=>1, "numero"=>646, "titre"=>"Acquérir en priorité des équipements reconditionnés", "ponderation"=>3, "texte_kpi"=>"% du parc reconditionné", "section"=>"achats-responsables", "created_at"=>"2019-06-03 14:10:14.228234", "updated_at"=>"2019-06-03 14:10:14.228234"}]
I want to access to ponderation value but I didn't find any docs related. I tried differents things but got errors messages with string conversion.
Thanks for the help!
Since records_array is an Array of Hashes you need to first select the row (Hash) you want and then access the desired column:
records_array.first['ponderation'] # or records_array[0]['ponderation']
=> 3
Btw, if you are on Rails, why don't you generate a model for practiques and use ActiveRecord?

Numeric sort in Manual (Legacy) index in Neo4j 3 is not working correctly

I'm using Legacy indexing (now called Manual indexing). After migration from Neo4j 2 to version 3 I have some problems with numeric sorting.
Example of correct statement in Neo4j 2:
queryContext.sort(new Sort(new SortField(AGE, SortField.INT, false)));
This stament should be changed for Neo4j 3 (Lucene 5):
queryContext.sort(new Sort(new SortField(AGE, SortField.Type.INT, false)));
But if you use this sort statement you will get an exception:
java.lang.IllegalStateException: unexpected docvalues type SORTED_SET for field 'firstName' (expected=SORTED). Use UninvertingReader or index with docvalues.
at org.apache.lucene.index.DocValues.checkField(DocValues.java:208)
at org.apache.lucene.index.DocValues.getSorted(DocValues.java:264)
at org.apache.lucene.search.FieldComparator$TermOrdValComparator.getSortedDocValues(FieldComparator.java:762)
at org.apache.lucene.search.FieldComparator$TermOrdValComparator.getLeafComparator(FieldComparator.java:767)
at org.apache.lucene.search.FieldValueHitQueue.getComparators(FieldValueHitQueue.java:183)
at org.apache.lucene.search.TopFieldCollector$SimpleFieldCollector.getLeafCollector(TopFieldCollector.java:164)
at org.neo4j.kernel.api.impl.index.collector.DocValuesCollector.replayTo(DocValuesCollector.java:297)
at org.neo4j.kernel.api.impl.index.collector.DocValuesCollector.getTopDocs(DocValuesCollector.java:275)
at org.neo4j.kernel.api.impl.index.collector.DocValuesCollector.getIndexHits(DocValuesCollector.java:150)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.search(LuceneLegacyIndex.java:346)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.query(LuceneLegacyIndex.java:261)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.query(LuceneLegacyIndex.java:205)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.query(LuceneLegacyIndex.java:217)
at org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeLegacyIndexQuery(StateHandlingStatementOperations.java:1440)
at org.neo4j.kernel.impl.api.OperationsFacade.nodeLegacyIndexQuery(OperationsFacade.java:1162)
at org.neo4j.kernel.impl.coreapi.LegacyIndexProxy$Type$1.query(LegacyIndexProxy.java:83)
at org.neo4j.kernel.impl.coreapi.LegacyIndexProxy.query(LegacyIndexProxy.java:365)
I think this is caused by new added statement in Neo4j indexer class (Neo4j is indexing field for sorting automatically now?). See in:
org.neo4j.index.impl.lucene.legacy.IndexType CustomType addToDocument( Document document, String key, Object value )
new line:
document.add( instantiateSortField( key, value ) );
and method instantiateSortField is creating SortedSetDocValuesField
So I changed my code to:
queryContext.sort(new Sort(new SortedSetSortField(AGE, false)));
This runs OK but sorting is not working because numbers are sorted as string. I see that "value" parameter is String every time in method "addToDocument". I think the root cause is explained it this old comment:
see comment in class org.neo4j.index.impl.lucene.legacy.IndexType CustomType
// TODO We should honor ValueContext instead of doing value.toString() here.
// if changing it, also change #get to honor ValueContext.
Am I missing some new way how to index, search and sort data in Neo4j 3 or this is really problem that values are indexed as string in Neo4j?
Simple unit test for Neo4j 2 and Neo4j 3 can be downloaded
Solution added by MishaDemianenko at GH issue

Fluent NHibernate join on multiple fields issue

Im currently researching how to port the Data Access Layer of an existing .NET 4.0 MVC 3 web application over to an entity framework. There are many reasons, but the primary one being due to thousands of stored procedures, adding just 1 field to a table results in 30 - 50 sproc edits!!
We are using MS SQL Server 2008 R2 and, ideally, we would like to use NHibernate and Fluent for mapping.
I have simplified the problem Im having into a simple example:
Imagine the following 2 tables:
'Products' Table
ID (INT)
DefaultName (NVARCHAR(128))
'Product Names' Table
ProductID (INT)
Name (NVARCHAR(128))
Culture (VARCHAR(10))
The Products table will contain a list of products, each of them will have a default, English, name. The Product Names table will contain the ID of the Product and many translations.
Currently, using stored procedures, we have the following:
SELECT Products.ID,
ISNULL(ProductNames.Name, Products.DefaultName) AS Name
FROM Products
LEFT JOIN ProductNames ON ProductNames.ProductID = Products.ID AND ProductNames.Culture = #Culture;
Note: #Culture is passed into the procedure
This always ensures a single Product with either a localised name or default (English) name is returned.
My question is: Is this possible to do at the Mapping level of Fluent NHibernate? I have been searching for days on 'How to join on 2 columns', but cant find a solution which works. It would seem odd if this is not possible in such a mature framework?
As an example of what I have been experimenting with:
public class ProductMap : ClassMap<Product> {
public ProductMap() {
Id(p => p.Id);
Join("ProductNames", pn => {
pn.Optional()
.KeyColumn("ProductID")
.Map(p => p.Name);
});
}
}
However, this results in the following exception:
More than one row with the given identifier was found: 109, for class: Product
This is because product 109 has 5 translations and thus all 5 cannot be mapped to a single string.
I have managed to use the 'HasMany<>' method to map all translations into a List within a Product. However, this is not what I need.
if the name is readonly then
public class ProductMap : ClassMap<Product> {
public ProductMap() {
Id(p => p.Id);
Map(p => p.Name).Formula("Select ISNULL(pn.Name, DefaultName) FROM ProductNames pn WHERE pn.ProductID = ID AND pn.Culture = '" + GetCUltureFromSomewhere() + "'");
}
}

Ruby on Rails Active Record Query - counting records

Hi I'm new to rails and developing an application to pull results from database in preparation for charting. I have the following code in my controller:
#statistic = OutstandingWorkIndex.find_by_sql ["SELECT Result_Set.Set_Code, Request.Specimen_Number ,
DATEDIFF('hh',Result_Set.Date_Time_Booked_In,current_timestamp) as HrsIn FROM iLabTP.Outstanding_Work_Index, iLabTP.Result_Set Result_Set, iLabTP.Request
WHERE Outstanding_Work_Index.Request_Row_ID = Result_Set.Request_Row_ID and Outstanding_Work_Index.Request_Row_ID = Request.Request_Row_ID and Result_Set.Set_code=?
order by Result_Set.Date_Time_Booked_In DESC", params[:set_code].upcase]
What I'd like to do is count the number of records returned in addition to the object from above which I then use to create and XML stream of paired values or use the google charts java script api in the view.
Do I need to issue commands like:
#statistic = OutstandingWorkIndex.find_by_sql ["SELECT Result_Set.Set_Code, Request.Specimen_Number ,
DATEDIFF('hh',Result_Set.Date_Time_Booked_In,current_timestamp) as HrsIn
FROM iLabTP.Outstanding_Work_Index, iLabTP.Result_Set Result_Set, iLabTP.Request
WHERE Outstanding_Work_Index.Request_Row_ID = Result_Set.Request_Row_ID and Outstanding_Work_Index.Request_Row_ID = Request.Request_Row_ID and Result_Set.Set_code=?
order by Result_Set.Date_Time_Booked_In DESC", params[:set_code].upcase].**count**
And if so does this result in the query being reissued?
Thanks
You should do:
#size = #statistic.size
It's well explained here.

Resources