This question already has an answer here:
using a variable in mongodb update
(1 answer)
Closed 2 years ago.
When I was using quick.db, I used to do this :
const table = new require('quick.db').table('table') // quick.db table
let guildID = msg.guild.id // snowflake generated by Discord; let's say it's equal to '1234567890'
table.set(`${guildID}.name`, `Cool Name`) // here, the variable name changes in function of guildID : so, to get 'Cool Name', I would have to look for '1234567890.name'.
And I am trying to do the same thing on mongoDB. In my view, it's a lot better and more complete than quick.db, but I still can't find how to do the same thing on mongo.
I guess that this is probably not possible, but I'd like to know if you have an idea about how I could replace this to easily get infos about a guild with its corresponding guildID.
I found a solution thanks to a comment that sent me to this page.
Even through with this method I can't create a value whose name is dependent of a variable directly as a field of the document, I can create one inside an object (the objects are selected with their names as strings, that's why I can insert a variable in that string)
collection.updateOne({id: "123"}, {$set: { ["object."+guildID+".name"]: "Cool Name" }}
Then, "Cool Name" can be found with:
collection.find({id: "123"}, {"object.1234567890.name": 1}) // note: I don't remember how to get a specific field of a document, please correct me or delete this note if you know what's correct
Related
This question already has an answer here:
Firebase query - Find item with child that contains string
(1 answer)
Closed 4 years ago.
In firebase, how can one go about running a query to find matches which have a specific word in the string?
for example querying all descriptions that have the word happy in them.
I am able to do this with JS but that means I have to load the entire DB which is over 300 items...
Cheers!
You don't have to download the entire DB for this (i assume you'r using realtime database over firestore).
You can filter your data mixing orderByChild() or orderByKey() or orderByValue() with query methods like startAt(), endAt() and equalTo().
For example, if your list of nodes url is
https://mydb-xxxx.firebaseio.com/parentnode/childnodeslist
You can query in this way:
// Find all nodes whose property myString is "hello"
var ref = firebase.database().ref("parentnode/childnodeslist");
ref.orderByChild("myString").equalTo('hello').once(‘value’).then(function(element){
console.log(element);
});
see the query doc and how to structure your data in firebase
EDIT: BASED ON COMMENTS:
If you want to make a full text search you can:
1) Make it client side
// assume "myString" is your param name
var word = 'hello';
var listOfItems = [];
firebase.database().ref("parentnode/childnodeslist").then(function(list){
listOfItems = list.map(function(item){
if( item.myString.indexOf(word) >= 0){
return {id: item.id, word: item.myString}
}
})
})
2) Use a third party tools like ElasticSearch (as suggested by #Frank-van-Puffelen) or Algolia
3) Use Cloud Functions
What is wrong with this query?
const db = firebase.firestore()
const query = db.doc(this.props.user.uid).collection('statements').orderBy('uploadedOn', 'desc').limit(50)
I get the following error:
Uncaught Error: Invalid document reference. Document references must have an even number of segments, but FrMd6Wqch8XJm32HihF14tl6Wui2 has 1
at new FirestoreError (index.cjs.js:346)
at Function.DocumentReference.forPath (index.cjs.js:15563)
at Firestore.doc (index.cjs.js:15368)
at UploadStatementPresentation.componentWillMount (UploadStatementPage.jsx:61)
at UploadStatementPresentation.componentWillMount (createPrototypeProxy.js:44)
at callComponentWillMount (react-dom.development.js:6872)
at mountClassInstance (react-dom.development.js:6968)
at updateClassComponent (react-dom.development.js:8337)
at beginWork (react-dom.development.js:8982)
at performUnitOfWork (react-dom.development.js:11814)
Since you haven't described what exactly you're trying to query, I'll just point out that all documents must be in a collection, without exception. So, if you say this:
db.doc(this.props.user.uid)
Firestore assumes that the string you're passing to doc() contains both the collection and document id separated by a slash. But this seems to be highly unlikely in your case. You need to determine which collection the uid is in, and use that first when you build the reference to the collection you want to query. Assuming that you do have a statements subcollection in the uid document, and that some other collection contains the uid document, you'll have to specify the full path like this:
db.collection('that-other-collection').doc(this.props.user.uid).collection('statements')
Of course, only you know the actual structure of your data.
If you want to get a collection of documents with querying, you don’t have to specify a document id. Below code should work in this case.
const query = db.collection('statements').orderBy('uploadedOn', 'desc').limit(50)
Or if you want to get the document, you can pass the document id to doc() method. In that case, the code should be.
const query = db.collection('statements').doc(this.props.user.uid)
For more details about querying firestorm data: https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0
For others having this issue, make sure that no document reference has an empty string.
I had this issue when using a get method with uid input as below and forgot to check if uid is empty
private fun getFullRef(uid: String): CollectionReference {
return ref.document(uid).collection(FireContact.SUB_PATH)
}
I created an ActivityNode (an Entry) and I can add custom fields with the
setFields(List<Field> newListField)
fonction.
BUT
I am unable to modify these fields. (In this case I try to modify the value of the field named LIBENTITE)
FieldList list = myEntry.getTextFields();
List<Field> updatedList = new ArrayList<Field>();
//I add each old field in the new list, but I modify the field LIBENTITE
for(Field myField : list){
if(myField.getName().equals("LIBENTITE")){
((TextField)myField).setTextSummary("New value");
}
updatedList.add(myField);
}
myEntry.setFields(updatedList);
activityService.updateActivityNode(myEntry);
This code should replace the old list of fields with the new one, but I can't see any change in the custom field LIBENTITE of myEntry in IBM connections.
So I tried to create a new list of fields, not modifying my field but adding a new one :
for(Field myField:list){
if(!myField.getName().equals("LIBENTITE")){
updatedList.add(myField);
}
}
Field newTextField = new TextField("New Value");
newTextField .setFieldName("LIBENTITE");
updatedList.add(newTextField );
And this code is just adding the new field in myEntry. What I see is that the other custom fields did not change and I have now two custom fields named LIBENTITE, one with the old value and the second with the new value, in myEntry.
So I though that maybe if I clear the old list of Fields, and then I add the new one, it would work.
I tried the two fonctions
myEntry.clearFieldsMap();
and
myEntry.remove("LIBENTITE");
but none of them seems to work, I still can't remove a custom field from myEntry using SBT.
Any suggestions ?
I have two suggestions, as I had (or have) similar problems:
If you want to update an existing text field in an activity node, you have to call node.setField(fld) to update the field in the node object.
Code snippet from my working application, where I'm updating a text field containing a (computed) start time:
ActivityNode node = activityService.getActivityNode(id);
node.setTitle(formatTitle()); // add/update start and end time in title
boolean startFound = false;
// ...
FieldList textfields =node.getTextFields();
Iterator<Field> iterFields = textfields.iterator();
while (iterFields.hasNext()) {
TextField fld = (TextField) iterFields.next();
if (fld.getName().equals(Constants.FIELDNAME_STARTTIME)) {
fld.setTextSummary(this.getStartTimeString()); // NOTE: .setFieldValue does *not* work
node.setField(fld); // write updated field back. This seems to be the only way updating fields works
startFound=true;
}
}
If there is no field with that name, I create a new one (that's the reason I'm using the startFound boolean variable).
I think that the node.setField(fld) should do the trick. If not, there might be a way to sidestep the problem:
You have access to the underlying DOM object which was parsed in. You can use this to tweak the DOM object, which finally will be written back to Connections.
I had to use this as there seems to be another nasty bug in the SBT SDK: If you read in a text field which has no value, and write it back, an error will be thrown. Looks like the DOM object misses some required nodes, so you have to create them yourself to avoid the error.
Some code to demonstrate this:
// ....
} else if (null == fld.getTextSummary()) { // a text field without any contents. Which is BAD!
// there is a bug in the SBT API: if we read a field which has no value
// and try to write the node back (even without touching the field) a NullPointerException
// will be thrown. It seems that there is no value node set for the field. We
// can't set a value with fld.setTextSummary(), the error will still be thrown.
// therefore we have to remove the field, and - optionally - we set a defined "empty" value
// to avoid the problem.
// node.remove(fld.getName()); // remove the field -- this does *not* work! At least not for empty fields
// so we have to do it the hard way: we delete the node of the field in the cached dom structure
String fieldName = fld.getName();
DeferredElementNSImpl fldData = (DeferredElementNSImpl) fld.getDataHandler().getData();
fldData.getParentNode().removeChild(fldData); // remove the field from the cached dom structure, therefore delete it
// and create it again, but with a substitute value
Field newEmptyField = new TextField (Constants.FIELD_TEXTFIELD_EMPTY_VALUE); // create a field with a placeholder value
newEmptyField.setFieldName(fieldName);
node.setField(newEmptyField);
}
Hope that helps.
Just so that post does not stay unanswered I write the answer that was in a comment of the initial question :
"currently, there is no solution to this issue, the TextFields are read-only map. we have the issue recorded on github.com/OpenNTF/SocialSDK/issues/1657"
I seem to be having a problem with assigning values to fields of a content item with a custom content part and the values not persisting.
I have to create the content item (OrchardServices.ContentManager.Create) first before calling the following code which modifies a field value:
var fields = contentItem.As<MyPart>().Fields;
var imageField = fields.FirstOrDefault(o => o.Name.Equals("Image"));
if (imageField != null)
{
((MediaLibraryPickerField)imageField).Ids = new int[] { imageId };
}
The above code works perfectly when against an item that already exists, but the imageId value is lost if this is done before creating it.
Please note, this is not exclusive to MediaLibraryPickerFields.
I noticed that other people have reported this aswell:
https://orchard.codeplex.com/workitem/18412
Is it simply the case that an item must be created prior to amending it's value field?
This would be a shame, as I'm assigning this fields as part of a large import process and would inhibit performance to create it and then modify the item only to update it again.
As the comments on this issue explain, you do need to call Create. I'm not sure I understand why you think that is an issue however.
I am working on an Orchard site that needs to be able to use some customized forms to create new content items.
To handle this I'm using a controller to display a form and then trying to create the new content items on post back by populating the dynamic items and then sending them through the ContentManagerService's Create() function.
This is working ok until I got to the content picker field I have as part of my content item.
In my project I have a content type of Question Record that has a SubmittedBy field that is a Content Picker Field.
Here is what I can see in the immediate window while processing the post back:
> dynamic q = _questionService.NewQuestion("Why doesn't this work?");
{Custom.Website.Models.Question}
base {Orchard.ContentManagement.ContentPart}: {Custom.Website.Models.Question}
IsNew: true
OriginalQuestion: "Why doesn't this work?"
Summary: null
> q.QuestionRecord
{Orchard.ContentManagement.ContentPart}
base {System.Dynamic.DynamicObject}: {Orchard.ContentManagement.ContentPart}
ContentItem: {Orchard.ContentManagement.ContentItem}
Fields: Count = 5
Id: 0
PartDefinition: {Orchard.ContentManagement.MetaData.Models.ContentPartDefinition}
Settings: Count = 0
TypeDefinition: {Orchard.ContentManagement.MetaData.Models.ContentTypeDefinition}
TypePartDefinition: {Orchard.ContentManagement.MetaData.Models.ContentTypePartDefinition}
Zones: {Orchard.UI.ZoneCollection}
> q.QuestionRecord.SubmittedBy
{Orchard.ContentPicker.Fields.ContentPickerField}
base {Orchard.ContentManagement.ContentField}: {Orchard.ContentPicker.Fields.ContentPickerField}
ContentItems: null
Ids: {int[0]}
The ContentItems property is read-only and the Ids when assigning a new int[] to the Ids array I get a System.ObjectDisposedException with the message: Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
Are there any workarounds to get this value set in code or do I need to create my own property to store the related content item ids? It would be very helpful to have the admin interface of the ContentPickerField also available.
Thanks.
If you have a reference to the ContentPickerField, you can assign it a value using the Ids property.
In example (assuming your content type has a part called Question which has a field called SubmittedBy):
var submittedByField = ((dynamic)q.ContentItem).Question.SubmittedBy;
sbmittedByField.Ids = new[] { submittedById };
As Bertrand mentioned, the format to access a content field is: contentItem.PartName.FieldName.
If you attached a field to a type directly via the admin, the part name has the same name as the type name, hence contentItem.TypeName.FieldName (where TypeName is actually the name of the implicitly created part).