I am dynamically building queries against a mongodb database. In doing this I am using query checking, using a library called 'mongodb-language-model'. It has proven to work great for many of the queries I have run.
However, when using this library against the following query:
{"name":"temp","$or":[{"binderId":"627e38f6e5ce...."},{"$expr":{"$eq":[{"$last":"$lineage"},"627e38f6e5ce15..."]}}],"teamId":"627e35b9e5ce..."}
I get the error:
SyntaxError: Expected "$binary", "$date", "$maxKey", "$minKey", "$numberDecimal", "$numberLong", "$oid", "$ref", "$regex", "$timestamp", "$undefined", or [^$] but "$" found.
This query returns a list of documents, matching based on the last item in an array within a document along with some other matches.
I have verified that if I use this query in a find like so it works fine:
db.collection.find({"name":"temp","$or":[{"binderId":"627e38f6e5ce...."},{"$expr":{"$eq":[{"$last":"$lineage"},"627e38f6e5ce15..."]}}],"teamId":"627e35b9e5ce..."})
I have tracked it down the to the usage of $last which is an alias for
{ $arrayElemAt: [ <array expression>, -1 ] }
I attempted to use this version of the expression in the query but still it fails with the same error with the library.
I also then attempted to report this to the package owner but it is part of the compass tooling. I did verify that the query works using the compass tooling
Related
I am trying to use MongoDB aggregation in a Meteor application. I am using Meteor 1.11, which uses MongoDB 4.2.8. I built and tested my aggregation pipeline with Robo 3T and also tested it with the Mongo shell. It works fine in those contexts, but I can't get it working in a Meteor method.
I narrowed the problem down to the match stage, which is first in the pipeline. When running in a Meteor method, this stage appears to match all documents in the collection. When run in Robo 3T, it returns 4 documents. Here's how I run it in a Meteor method:
MyCollection
.rawCollection()
.aggregate([{$match: {vocabularyName: "IPF", type: "T"}}])
.toArray()
.then(docs => {
console.log(`got ${docs.length} docs`);
console.log(docs[0]);
console.log(docs[1]);
})
.catch(error => console.log(`error ${error} in db_methods`));
Every document in MyCollection contains a "type" field with varying values; most (but not all) contain a "vocabularyName" field. When I run this in a Meteor method, the returned array size matches the total document count and the first two results documents contain no vocabularyName field at all, and "type: 'S'". Which does not make any sense.
On a guess, I also tried this pipeline, but it made no difference:
[ {"$match": {"$and": [{ "vocabularyName": "IPF"}, {"type": "T"}]}} ]
Using adminMongo as web-ui for MongoDB, I want to filter and order the documents. Filtering works simple:
{
"status": 4
}
But additionally, all documents should be sorted by date field, which is a unix timestamp. In MySQL I would simply add ORDER BY date DESC but as a newbie, It's not clear for me how to do this in adminMongo.
I took a look in the documentation. They execute js code with methods. To get in this, I used the shell and could get my expected data result using the following code:
db.getCollection('my-collection').find({"status": 4}).sort({date: -1})
However this works on the shell, it creates an error in adminMongo. Seems that adminMongo expects a json document. So we've 2 syntax variants? It's confusing me, since on SQL we've SQL and don't care if we write SQL in any programming language, admin ui or directly on the shell.
I think I've to convert the find method to json, but don't know why. According to the docs, we can use $sort as $sort: { 'date': -1}. Calling aggreagate() method on the collection, this works. On adminMongo, I got an error when trying to send something like
{
{ "$sort": { 'date': -1} }
}
What is the right syntax which I need to use on adminMongo? Where is documented, how I can convert methods like aggregate which are used for sorting, to this syntax?
What I'm trying to achieve in here is to update a given set of documents that contain a given set of fields, either one, another or both.
I have two questions actually for this matter...
Can MongoDB process fields that aren't present in the document being processed? Like what I'm trying to achieve here, sum two fields, and if one is null just sum 0.
And the other one is the error that I'm getting in the query...
db.getCollection('my_collection').update({'$or': [{
'a_field': 1}, {
'another_field': 1
}
]},
{'$set': {
'another_field': {
'$sum': [
'$a_field', '$another_field'
]
}
},
'$unset': {'a_field': ''}})
Giving me the following error...
The dollar ($) prefixed field '$sum' in 'another_field.$sum' is not valid for storage.
There is no $sum UPDATE operator in mongodb and hence the error. The one you are confused with is an aggregation operator and can only be used to query data in a fashion.
Also, the operator you are looking at is $inc, however you CANNOT update the document in the fashion you are trying to. There is an OPEN ticket for this feature to mongodb. Ticket
Hope this clarifies
See this answer for more on achieving what you are trying to do.
My user database structure is as follows
{ _id:123, fname:Name,
projects:[
{projectid:123,
createdby:123}
]
}
{ _id:456, fname:Name,
projects:[
{projectid:789,
createdby:456,
teammembers:[{memberid:123},{memberid:654}]
}
]
}
I am trying to get the list of projects where either i am the creator or i am one of the teammembers. I have trued the following query
db.user.find({"$or":[{"projects.teammembers.memberid":"123"},{"projects.createdby":"123"}],{projects:1})
This query gives me projects where i am not a member also.
If i put the column restriction as
projects.$.memberid:1
mongo throws this error.
"Positional operator does not match the query specifier."
I know by changing the structure of projects.teammembers to just array will work but for now the change process will take time.
Any solution?
You are trying to execute a query on a "2 levels array" that's why you get :
projects.$.memberid:1
So, you must to use the $ proection operator, for "search in each table values in their own table".
Try with
db.user.find({"$or":[{"projects.teammembers.$.memberid":"123"},{"projects.createdby":"123"}],{projects:1})
Or take a look at this doc: Projection doc
Sorry for my english
I was able to solve the problem using aggregate command.
Here's what i did
collection.aggregate([{"$unwind":"$projects"},
{"$match":{"$or":[{"projects.createdby":"user1"},
{"projects.teammembers.memberid":"user1"}]}},
{"$project":{"projects":1}}]
It gives the list of projects where i am the creator and also only those list of projects where i am a team member.
I need to make a query using aggregate in the MongoDB, but as the meteor does not support'm trying to use the extension server-aggregation.
I'm using the code on the server like this:
var result = aggregates('publicadores',[{$match: {_id : _id}},{ $unwind: '$relatorios' },{ $sort: {'relatorios.mes': -1 }}]);
The consultation is being done correctly, but when passing data by Publish Meteor is returning the following error:
Exception from sub MvPSGj5bf2jHFsRng Error: Publish function returned an array of non-Cursors
Does anyone know how to resolve this error, or some other way to apply the aggregate in Meteor?
You can try https://atmospherejs.com/meteorhacks/aggregate packages for MongoDB