RethinkDB: how can I query nested arrays? - nested

I have a person object in RethinkDB that looks like this:
{
"email": "user#domain.com",
"orders": {,
"id": 1,
"additionalInvoices": [
{
"description": "Bananas",
"stripeChargeId": "ch_333"
},
{
"description": "Apples",
"stripeChargeId": "ch_444"
}
]
}
}
Except no results are returned. Am I allowed to nest contains() functions? What's the best way to get the results I want?
Edit: I've also tried pluck() and describing the data structure, per this example of using nested datastructures in the RethinkDB docs - I thought this works, but it gives an empty object matching the query as the only result:
rethink.db(DATABASE).table(TABLE).pluck(
{orders: [{additionalInvoices: [{'stripeChargeId': chargeID}]}]}
).run(dbConnection, function(err, results) {
if ( err ) {
cb(err)
return;
}
toOne(results, cb)
})

Related

Mongoose - Return a single document instead of an array of documents with Aggregate

Before starting to use aggregate in order to create a timestamp of the document, I was using findOne so I could get a single object but now I'm getting an array with a single object. Is it possible to make the query return a single object instead of an array? Thank you in advance.
Query that I'm using:
News.aggregate()
.match({ '_id': n })
.project({ 'title': true, 'text': true, 'timestamp': { '$subtract': ['$date', new Date('1970-01-01')] } })
What is returning:
[
{
"_id": "5b9650beae847b1e5866cace",
"title": "Notícia 2",
"text": "Texto da Notícia 2",
"timestamp": 1543807353257
}
]
What I'd like to get returned:
{
"_id": "5b9650beae847b1e5866cace",
"title": "Notícia 2",
"text": "Texto da Notícia 2",
"timestamp": 1543807353257
}
Aggregate method returns an array; this is the defined behavior. If you want to adapt this behavior to your way, you can either re-create your own aggregate function; or deal with the array at every call; like :
async function aggregate(model, func) {
const aggregateObject = func(News.aggregate());
const ret = await aggregateObject.exec();
// Deal with the fact there is no answer
if (ret && ret.length) {
return ret[0];
}
return false;
}
const directData = await aggregate(News, (aggregateObj) => {
return aggregateObj
.match(...)
.project(...);
});

MongoDB: How to query field array by _id

how to get the specific message by _id.
I have a database schema as shown below:
{
"_id": ObjectID("5846eedaf0b51ed02ed846e2"),
"name": "conversation name"
"messages": [
{
"_id": ObjectID("584820a96866b6283361a4b9"),
"content": "hello",
"status": 0,
"type": 0
},
{
"_id": ObjectID("584820d56866b6283361a4ba"),
"content": "voices/1481122005696.mp3",
"status": 0,
"type": 3
}
]
}
db.collection.find({}, {
'messages': {
$elemMatch: {
'_id': ObjectId("584820a96866b6283361a4b9")
}
}
})
This will match on all documents in your collection, and return the matching array subfield in the projection. See the link posted in Yogesh's comment.
Since you tagged mongoose, I put it like this, but the query syntax is valid because is part of mongoDB query syntax:
Conversation.findOne({
"messages._id": "584820a96866b6283361a4b9"
}, function(err, document){
if (err) {
console.log(err)
return
}
var message = document.messages.id("584820a96866b6283361a4b9")
})
The finOne() method will return the full parent document with all the messages (subdocuments) and other properties. You then need to filter out the subdocument. Mongoose provides a way to do this easily with: document.messages.id("584820a96866b6283361a4b9") where document would be the data object passed to the find callback
See:
Match a Field Without Specifying Array Index on
https://docs.mongodb.com/v3.2/tutorial/query-documents/#query-on-arrays

Use mongoose / mongodb to $pull nested data from an array

say I have this array property ('articles') on a Mongoose schema:
articles: [
{
kind: 'bear',
hashtag: 'foo'
},
{
kind: 'llama',
hashtag: 'baz',
},
{
kind: 'sheep',
hashtag: 'bar',
}
]
how can I use
$pull https://docs.mongodb.org/manual/reference/operator/update/pull/
to remote objects from this array by checking the value of hashtag to see if it matches a pattern?
For example, if I want to remove an object in the articles array where hashtag='foo'.
My best guess is the following, but it doesn't seem to work:
var data = {
"$pull": {
"articles": {
"$elemMatch": {
"hashtag": "foo"
}
}
}
};
Model.update({},data); //doesn't quite work
this one seems to work:
var data = {
"$pull": {
"articles": {
"hashtag": 'foo'
}
}
};
Model.update({},data); //seems to work
if you have a better solution or if you can show an alternate solution please provide an answer thank you
The $pull operator is basically a "mini query" in itself, and as such operators like $elemMatch become irrelevant as the "query" is directly performed on each array member anyway.
As such:
Model.update(
{},
{ "$pull": { "articles": { "hashtag": "foo" }},
{ "multi": true },
function(err,numAffected) {
// handle result here
}
)
So it is looking for the matching properties within the ( correct ) specified array in all array documents, and then removing them where there is a match.
The .update() also just returns the number of affected documents, and is usually used with { "multi": true } when you expect more than one document to be updated.
If you are just looking for "one" document, or expect the modified document in response, then use .findOneAndUpdate() instead:
Model.findOneAndUpdate(
{},
{ "$pull": { "articles": { "hashtag": "foo" }},
{ "new": true },
function(err,numAffected) {
// handle result here
}
)
Though not really practical without any selection criteria, since this just updates the first document found in the collection.

Using $in in MongooseJS with nested objects

I've been successfully using $in in my node webservice when my mongo arrays only held ids. Here is sample data.
{
"_id": {
"$oid": "52b1a60ce4b0f819260bc6e5"
},
"title": "Sample",
"team": [
{
"$oid": "52995b263e20c94167000001"
},
{
"$oid": "529bfa36c81735b802000001"
}
],
"tasks": [
{
"task": {
"$oid": "52af197ae4b07526a3ee6017"
},
"status": 0
},
{
"task": {
"$oid": "52af197ae4b07526a3ee6017"
},
"status": 1
}
]
}
Notice that tasks is an array, but the id is nested in "task", while in teams it is on the top level. Here is where my question is.
In my Node route, this is how I typically deal with calling a array of IDs in my project, this works fine in the team example, but obviously not for my task example.
app.get('/api/tasks/project/:id', function (req, res) {
var the_id = req.params.id;
var query = req.params.query;
models.Projects.findById(the_id, null, function (data) {
models.Tasks.findAllByIds({
ids: data._doc.tasks,
query: query
}, function(items) {
console.log(items);
res.send(items);
});
});
});
That communicates with my model which has a method called findAllByIds
module.exports = function (config, mongoose) {
var _TasksSchema = new mongoose.Schema({});
var _Tasks = mongoose.model('tasks', _TasksSchema);
/*****************
* Public API
*****************/
return {
Tasks: _Tasks,
findAllByIds: function(data, callback){
var query = data.query;
_Tasks.find({_id: { $in: data.ids} }, query, function(err, doc){
callback(doc);
});
}
}
}
In this call I have $in: data.ids which works in the simple array like the "teams" example above. Once I nest my object, as with "task" sample, this does not work anymore, and I am not sure how to specify $in to look at data.ids array, but use the "task" value.
I'd like to avoid having to iterate through the data to create an array with only id, and then repopulate the other values once the data is returned, unless that is the only option.
Update
I had a thought of setting up my mongo document like this, although I'd still like to know how to do it the other way, in the event this isn't possible in the future.
"tasks": {
"status0": [
{
"$oid": "52995b263e20c94167000001"
},
{
"$oid": "529bfa36c81735b802000001"
}
],
"status1": [
{
"$oid": "52995b263e20c94167000001"
},
{
"$oid": "529bfa36c81735b802000001"
}
]
}
You can call map on the tasks array to project it into a new array with just the ObjectId values:
models.Tasks.findAllByIds({
ids: data.tasks.map(function(value) { return value.task; }),
query: query
}, function(items) { ...
Have you try the $elemMatch option in find conditions ? http://docs.mongodb.org/manual/reference/operator/query/elemMatch/

unable to get count in mongodb collection.find

I am using mongoose ODM for a application. I am trying to count the number of items returned by a model like this:
app.post("/verifyLogin",function(request,response){
var usr=request.body.username;
var pass=request.body.password;
response.send(userModel.find({$and:[{username:"admin"},{password:"admin"}]}).count());
});
But i get in return:
{
"options": {
"populate": {}
},
"_conditions": {
"$and": [
{
"username": "admin"
},
{
"password": "admin"
}
]
},
"_updateArg": {},
"op": "count"
}
I expected a number :(
One way of doing this is to use Model.count method, in your case:
userModel.count({$and:[{username:"admin"},{password:"admin"}]}, function(err, result) {
if (err) {
//handle errors
} else {
response.send({count :result});
}
});
Also: you're in node.js world - use callbacks.
The result you're getting now is the result of the count call on the Model.find() result (which, i think, is a query object), not the count of the query results.

Resources