How to delete all documents with safe mode? - mongodb

remove() method without any argument removes all documents inside the collection.
$this->db->$collection->remove();
But how to remove all documents with safe mode?
What should be the first argument of remove?
passing array('safe' => true) as first argument doesn't delete all document because it's treated like a filter with key 'safe'.
$this->db->$collection->remove(array('safe' => true));

You need to pass that as second parameter in the remove call :
http://php.net/manual/en/mongocollection.remove.php
$this->db->$collection->remove(array(),array('safe' => true));

Related

AngularFire valueChanges with idField and non-existent document

If I call valueChanges on a Firestore document that doesn't exist, it returns undefined:
this.afs.doc('bad_document_ref').valueChanges().subscribe(snapshot => {
console.log(snapshot) // undefined
});
But if I call valueChanges on the same bad ref, but I pass in the idField parameter, it returns an object with just the id:
this.afs.doc('bad_document_ref').valueChanges({ idField: 'custom_doc_id' }).subscribe(snapshot => {
console.log(snapshot) // { custom_doc_id: 'bad_document_ref' }
});
I would like for the two above examples to return the same thing. I can do this by adding a pipe:
this.afs.doc('bad_document_ref').valueChanges({ idField: 'custom_doc_id' })
.pipe(map(snapshot => {
if(!snapshot) return undefined;
if (Object.keys(snapshot).length === 1 && Object.keys(snapshot)[0] === 'custom_id_field') {
return undefined;
}
return snapshot;
}))
.subscribe(snapshot => {
console.log(snapshot) // undefined
});
Is there a reason why the first two examples don't return the same thing? It seems like the logical thing to do, for the sake of consistency. Maybe there is a reason I'm not thinking of for why they would return different values?
The valueChange() method is basically the current state of your collection. You can listen for changes on the collection’s documents by calling valueChanges() on the collection reference. It returns an Observable of data as a synchronized array of JSON objects. All Snapshot metadata is stripped and just the document data is included.
When you pass an option object with an idField key containing a string like .valueChanges({ idField: 'propertyId' }); , it returns JSON objects with their document ID mapped to a property with the name provided by idField.
When the document doesn't actually exist, you would expect it to return nothing. In the first piece of code, you are not providing idField and the document doesn't exist, the observable returned undefined, which is justified. However, when you specify idField in the second piece of code, you basically say that when you return the data, you want the id of the document to be added to it. However if there is no data, there should not be any value returned, which is what you wanted to point out and which is quite justified. In other words, if the document does not exist, ideally it should return undefined even if you specify the idField parameter.
A GitHub link pointing towards the same issue says that the appropriate behavior is addressed in version 7 api.
Another GitHub link to be followed on this.
I am using:
angularFirestore.collection<Item>('items');
Note that for the object mapped I use <Item>, so maybe you can use it in your doc.

How can I upsert a record and array element at the same time?

That is meant to be read as a dual upsert operation, upsert the document then the array element.
So MongoDB is a denormalized store for me (we're event sourced) and one of the things I'm trying to deal with is the concurrent nature of that. The problem is this:
Events can come in out of order, so each update to the database need to be an upsert.
I need to be able to not only upsert the parent document but an element in an array property of that document.
For example:
If the document doesn't exist, create it. All events in this stream have the document's ID but only part of the information depending on the event.
If the document does exist, then update it. This is the easy part. The update command is just written as UpdateOneAsync and as an upsert.
If the event is actually to update a list, then that list element needs to be upserted. So if the document doesn't exist, it needs to be created and the list item will be upserted (resulting in an insert); if the document does exist, then we need to find the element and update it as an upsert, so if the element exists then it is updated otherwise it is inserted.
If at all possible, having it execute as a single atomic operation would be ideal, but if it can only be done in multiple steps, then so be it. I'm getting a number of mixed examples on the net due to the large change in the 2.x driver. Not sure what I'm looking for beyond the UpdateOneAsync. Currently using 2.4.x. Explained examples would be appreciated. TIA
Note:
Reiterating that this is a question regarding the MongoDB C# driver 2.4.x
Took some tinkering, but I got it.
var notificationData = new NotificationData
{
ReferenceId = e.ReferenceId,
NotificationId = e.NotificationId,
DeliveredDateUtc = e.SentDate.DateTime
};
var matchDocument = Builders<SurveyData>.Filter.Eq(s => s.SurveyId, e.EntityId);
// first upsert the document to make sure that you have a collection to write to
var surveyUpsert = new UpdateOneModel<SurveyData>(
matchDocument,
Builders<SurveyData>.Update
.SetOnInsert(f => f.SurveyId, e.EntityId)
.SetOnInsert(f => f.Notifications, new List<NotificationData>())){ IsUpsert = true};
// then push a new element if none of the existing elements match
var noMatchReferenceId = Builders<SurveyData>.Filter
.Not(Builders<SurveyData>.Filter.ElemMatch(s => s.Notifications, n => n.ReferenceId.Equals(e.ReferenceId)));
var insertNewNotification = new UpdateOneModel<SurveyData>(
matchDocument & noMatchReferenceId,
Builders<SurveyData>.Update
.Push(s => s.Notifications, notificationData));
// then update the element that does match the reference ID (if any)
var matchReferenceId = Builders<SurveyData>.Filter
.ElemMatch(s => s.Notifications, Builders<NotificationData>.Filter.Eq(n => n.ReferenceId, notificationData.ReferenceId));
var updateExistingNotification = new UpdateOneModel<SurveyData>(
matchDocument & matchReferenceId,
Builders<SurveyData>.Update
// apparently the mongo C# driver will convert any negative index into an index symbol ('$')
.Set(s => s.Notifications[-1].NotificationId, e.NotificationId)
.Set(s => s.Notifications[-1].DeliveredDateUtc, notificationData.DeliveredDateUtc));
// execute these as a batch and in order
var result = await _surveyRepository.DatabaseCollection
.BulkWriteAsync(
new []{ surveyUpsert, insertNewNotification, updateExistingNotification },
new BulkWriteOptions { IsOrdered = true })
.ConfigureAwait(false);
The post linked as being a dupe was absolutely helpful, but it was not the answer. There were a few things that needed to be discovered.
The 'second statement' in the linked example didn't work
correctly, at least when translated literally. To get it to work, I had to match on the
element and then invert the logic by wrapping it in the Not() filter.
In order to use 'this index' on the match, you have to use a
negative index on the array. As it turns out, the C# driver will
convert any negative index to the '$' character when the query is
rendered.
In order to ensure they are run in order, you must include bulk write
options with IsOrdered set to true.

How to unset field from Document

I have one document in which I want to remove one field. I got answer from Here. But, It is for core PHP code and I want in CakePHP how to unset field from document.
I tried following code in CakePHP.
$this->MyModal->id = $id;
$this->MyModal->updateAll(
array('myField' => array('$exists' => true)),
array('unset' => array('myField' => true))
);
Edit
I also tried
$this->MyModal->updateAll(
array('$unset' => array('myField' => 1))
);
But it does not work.How can unset field?
It looks like you're using wrong the update all method. First you must provide an array with the new values you want for your fields and then you should pass an array with the search criteria. So in order for it to work you could write something like
$conditions=array('myField'=>array('$exists'=>true));
$this->MyModal->updateAll(
array('$unset'=>array('myfield'=>1)),
$conditions//array of search conditions
)

MongoDb replacing a document and inserting when non-existant

I want to replace a document when this already exists and if it doesn't I want it inserted.
How can I do that in mongoDb?
I need something like this, but in one query:
find by a "where statement"
if exists, replace whole document
else, insert
Thank you!
you could also use the save operation, that is much faster than the update (x70 faster from my tests), and is adapt to your purpose, but in case remember to give in input the whole document
Use collection update.
In the example below, the first update call will "insert or replace" the document (including name field from the query). In the second the update call will insert the document or just update Joe's job leaving the rest of the document intact. The difference is the "$set" operation.
<?php
$c->update(
array("name" => "joe"),
array("username" => "joe312", "job" => "Codemonkey"),
array("upsert" => true));
$c->update(
array("name" => "joe"),
array("$set" => array("job" => "Bartender")),
array("upsert" => true));
?>

Zend Framework : Setting up default values for part of the multicheckbox element options not possible

I'm writing this question cause I have difficulties setting up default values for a _MultiCheckbox element of a Zend Framework 1.9.3.
I create Zend_Form_Element_MultiCheckbox with multiple options like this:
$multiCheckbox = new Zend_Form_Element_MultiCheckbox( 'elId',
array ( 'disableLoadDefaultDecorators' =>true ) );
$multiCheckbox ->setName( 'elId' )
->setLabel('elId')
->setRequired( false )
->setAttrib('class', 'inputtext')
->setDecorators( array( 'ViewHelper' ) )
->setMultiOptions( $options );
where the $options array is an associative array 'key' => 'value'. The field is displayed just fine and I can get all the checked values for that element.
When returning to that page I need to restore from the DB the whole list of options again and mark the checked ones. I have tried to do it like that:
$multiCheckbox ->setValue( $defaults );
where $default is array, containing elements of type 'checked_option_field_id' => true(eg. array( '1222' => true, '1443' => true ) ). That action checks ALL the checkboxes and not only the once I need and I have passed to the setValue() method.
I have tried to pass just an array containing elements of type 'checked_option_field_id', (eg. array( '1222', '1443' ) )but that also doesn't work - NONE of the checkboxes is checked.
I have used the form setDefaults() method with those two kinds of arrays, but the results are same - as this method uses again setValue() for each element.
MultiCheckbox element is rendered like that ( result when try to set checked value for only one option ):
<label for="elId-1222"><input type="checkbox" name="elId[]" id="elId-1222" value="1222" checked="checked" class="inputtext">BoRoom </label><br />
<label for="elId-1443"><input type="checkbox" name="elId[]" id="elId-1443" value="1443" checked="checked" class="inputtext">BoRoom Eng2 </label><br/>
That element populates the checked option values in the elId[] array. That is the element name.
setDefaults() form method gets all form elements by name and commit their default values by calling setDefault() form method and after that setValue() element method. So my multicheckbox element has name elId ( it does not get all the element options one by one ) and set default values for all options instead of just the given in the array.
That is how I see it and I can't find solution how to set default values only for some of the options of a multicheckbox element.
Chris is correct that setValue() expects an array of values to be 'checked' (not an array of bool values keyed by your option IDs).
If you are looking for the logic behind the form generation, don't look at the Zend_Form_Element object (or the many extended elements from it), look at the Zend_View_Helper objects. Specifically the Zend_View_Helper_FormRadio object.
When generating the HTML the options array is looped, then the value is checked against the value array - the array passed to setValue(), using in_array().
From Zend_View_Helper_FormRadio line: 150
// is it checked?
$checked = '';
if (in_array($opt_value, $value)) {
$checked = ' checked="checked"';
}
Not sure what that's not working for you, but if you're passing:
$element->setMultiOptions(array('1111' => 'Some Label',
'2222' 'Some Other Label',
'3333', 'Not Selected Label'));
$element->setValue(array('1111','2222');
It should work. Maybe if you could include some code it would be easier to see what's going on?
The setValue() expects a array with those values that need to be checked, in this case for example you need to pass a array with values 1222, 1443 for them to be marked as checked.
You need to serialize the checkbox value before insert in database. To show the database value selected again you have to unserialize the data to show.
The details you can read from following link
http://abser-web-tips.blogspot.com/2010/09/zend-framework-multiple-check-box.html
Thanks