Deleting a document from a mongodb collection - mongodb

I have a collection called customers and it contains documents.
I have written a function to delete a document using the field and its value which takes as arguments.
But it doesn't remove any customer as expected. Can anybody show me where I have gone wrong?
function (fieldName, value) {
db.customers.remove({x : y});
}
I called the function from the mongo terminal as below.
db.loadServerScripts();
removeDocument("firstName", "Sam");
Thanks

Rewrite your function so that the arguments become part of the query object. You can do this using either computed property or bracket notation.
Using computed property:
function removeDocument(fieldName, value) {
db.customers.remove({[fieldName]: value});
}
Using bracket notation
function removeDocument(fieldName, value) {
var query = {};
query[fieldName] = value;
db.customers.remove(query);
}

db.collection.remove is deprecated so use deleteOne or deleteMany(For deleting multiple documents)

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.

Get MongoDb results and count of aggregation using C# driver

I'm using Aggregation to do a query and lookup. What's the most efficient way of returning both the results and count using one server call?
I've seen there is a way to do this using Facets, however, I'd like to do this using a Fluent expression with typed classes so I can abstract the logic into a generic extension method.
My current code looks something like this:
collection
.Aggregate ()
.Match (Builders<Order>.Filter...)
.Lookup (...)
.Project<Order> (Builders<Order>.Projection.Exclude ...)
I believe you are looking for the $group operator.
collection
.Aggregate ()
.Match (Builders<Order>.Filter...)
.Lookup (...)
.Project<Order> (Builders<Order>.Projection.Exclude ...)
.Group(x => x.OrderId, g => new { ResultCount = g.Count(), Data = g.Select(x => new Order { SomeOrderProperty = x.AnotherOne}).ToList() }).FirstOrDefault();
This will give you an anonymous object containing your count and results in one. I dont know how your entity looks so I have assumed some names but you should be able to infer from this.

How to sort this array of results?

Here is my query that attempts to sort an array of MongoDB documents based on a derived field called expiresAt. expiresAt is a Date object that represents the date string stored in doc.expirationDate.
It fails with an error TypeError: ... .sort({}) is not a function (shell):5
db.tokens.find().map(function(doc) {
var expiryDate = new Date(doc.credentialsMap.linkedin.expirationDate);
doc.expiresAt = expiryDate;
return doc;
}).sort({'expiresAt': -1});
What am I doing wrong? It's unclear to me exactly what return type map provides. If it's a cursor then why isn't sort supported? It's clearly available in the docs.
cursor.map() returns a Java script array.
The way you're calling sort() assumes that the return value is a MongoDB cursor, that's why it fails.
You'd have to use the regular Array.sort syntax.
For example, to have your map results sorted in descending order, use the following:
db.tokens.find().map(function(doc) {
var expiryDate = new Date(doc.credentialsMap.linkedin.expirationDate);
doc.expiresAt = expiryDate;
return doc;
}).sort(function(a,b) { return b.expiresAt - a.expiresAt});

CouchDB Map/Reduce view query from Ektorp

I'm trying to execute a query from java against a Map/Reduce view I have created on the CouchDB.
My map function looks like the following:
function(doc) {
if(doc.type == 'SPECIFIC_DOC_TYPE_NAME' && doc.userID){
for(var g in doc.groupList){
emit([doc.userID,doc.groupList[g].name],1);
}
}
}
and Reduce function:
function (key, values, rereduce) {
return sum(values);
}
The view seems to be working when executed from the Futon interface (without keys specified though).
What I'm trying to do is to count number of some doc types belonging to a single group. I want to query that view using 'userID' and name of the group as a keys.
I'm using Ektorp library for managing CouchDB data, if I execute this query without keys it returns the scalar value, otherwise it just prints an error saying that for reduce query group=true must be specified.
I have tried the following:
ViewQuery query = createQuery("some_doc_name");
List<String> keys = new ArrayList<String>();
keys.add(grupaName);
keys.add(uzytkownikID);
query.group(true);
query.groupLevel(2);
query.dbPath(db.path());
query.designDocId(stdDesignDocumentId);
query.keys(keys);
ViewResult r = db.queryView(query);
return r.getRows().get(0).getValueAsInt();
above example works without 'keys' specified.
I have other queries working with ComplexKey like eg:
ComplexKey key = ComplexKey.of(userID);
return queryView("list_by_userID",key);
but this returns only a list of type T (List) - using CouchDbRepositorySupport of course - and cannot be used with reduce type queries (from what I know).
Is there any way to execute the query with reduce function specified and a complex key with 2 or more values using Ektorp library? Any examples highly appreciated.
Ok, I've found the solution using trial and error approach:
public int getNumberOfDocsAssigned(String userID, String groupName) {
ViewQuery query = createQuery("list_by_userID")
.group(true)
.dbPath(db.path())
.designDocId(stdDesignDocumentId)
.key(new String[]{userID,groupName});
ViewResult r = db.queryView(query);
return r.getRows().get(0).getValueAsInt();
}
So, the point is to send the complex key (not keys) actually as a single (but complex) key containing the String array, for some reason method '.keys(...)' didn't work for me (it takes a Collection as an argument). (for explanation on difference between .key() and .keys() see Hendy's answer)
This method counts all documents assigned to the specific user (specified by 'userID') and specific group (specified by 'groupName').
Hope that helps anybody executing map/reduce queries for retrieving scalar values from CouchDB using Ektorp query.
Addition to Kris's answer:
Note that ViewQuery.keys() is used when you want to query for documents matching a set of keys, not for finding document(s) with a complex key.
Like Kris's answer, the following samples will get document(s) matching the specified key (not "keys")
viewQuery.key("hello"); // simple key
viewQuery.key(documentSlug); // simple key
viewQuery.key(new String[] { userID, groupName }); // complex key, using array
viewQuery.key(ComplexKey.of(userID, groupName)); // complex key, using ComplexKey
The following samples, on the other hand, will get document(s) matching the specified keys, where each key may be either a simple key or a complex key:
// simple key: in essence, same as using .key()
viewQuery.keys(ImmutableSet.of("hello"));
viewQuery.keys(ImmutableSet.of(documentSlug1));
// simple keys
viewQuery.keys(ImmutableSet.of("hello", "world"));
viewQuery.keys(ImmutableSet.of(documentSlug1, documentSlug2));
// complex key: in essence, same as using .key()
viewQuery.keys(ImmutableSet.of(
new String[] { "hello", "world" } ));
viewQuery.keys(ImmutableSet.of(
new String[] { userID1, groupName1 } ));
// complex keys
viewQuery.keys(ImmutableSet.of(
new String[] { "hello", "world" },
new String[] { "Mary", "Jane" } ));
viewQuery.keys(ImmutableSet.of(
new String[] { userID1, groupName1 },
new String[] { userID2, groupName2 } ));
// a simple key and a complex key. while technically possible,
// I don't think anybody actually does this
viewQuery.keys(ImmutableSet.of(
"hello",
new String[] { "Mary", "Jane" } ));
Note: ImmutableSet.of() is from guava library.
new Object[] { ... } seems to have same behavior as ComplexKey.of( ... )
Also, there are startKey() and endKey() for querying using partial key.
To send an empty object {}, use ComplexKey.emptyObject(). (only useful for partial key querying)

Linq To NHibernate Plus sql user defined function

I have a rather large linq-to-nhibernate query. I now need to add a filter based on a user-defined function written in t-sql that i have to pass parameters into. In my case, I need to pass in a zipcode that the user types in and pass it to the t-sql function to filter by distance from this zip. Is this possible, or do i need to rewrite my query using the ICriteria api?
i did find a solution:
Note the NHibernate query (nquery) which has RegisterCustomAction:
private void CallZipSqlFunction(ListingQuerySpec spec, IQueryable<Listing> query)
{
var nQuery = query as NHibernate.Linq.Query<Listing>;
//todo: find some way to paramaterize this or use linq-to-nh and not criteria to call the function
// so i don thave to check for escape chars in zipcode
if (spec.ZipCode.Contains("'"))
throw new SecurityException("invalid character");
//yuck!
var functionString = "dbo.GetDistanceForListing('" + spec.ZipCode + "',{alias}.ID) as Distance";
//create a projection representing the function call
var distance = Projections.SqlProjection(functionString, new[] { "Distance" }, new IType[] { NHibernateUtil.String });
//create a filter based on the projection
var filter = Expression.Le(distance, spec.ZipCodeRadius.Value);
//add the distance projection as order by
nQuery.QueryOptions.RegisterCustomAction(x => x.AddOrder(Order.Asc(distance)));
//add teh distance filter
nQuery.QueryOptions.RegisterCustomAction(x => x.Add(filter));
}