GoInstant: Match a single array element with $goQuery? - goinstant

Is it possible yet to query a key with an array value by a single array element with GoInstant GoAngular? For example, if querying a list of items with the following keys/properties, can I select only items that belong to a single user?
item: {
name: 'Item name',
description: 'A longer description of the item and its details',
category: 'Business',
user_ids: [1,3,7,15] //This is an array of user id's because items
//have a many-to-many relationship with users
}
I tried this query but it does not return anything:
var queryResults = $goQuery('items', { user_ids: 1 }, { limit: 10 }).$sync();
I believe this is the proper syntax according to the MongoDB documentation, but I'm not sure if GoInstant has implemented this operator yet. Any help will be greatly appreciated.

This should work as you expect, it's definitely a bug! Stay tuned, I'll update this Answer once it's been fixed.

Related

Mongoose $in [ObjectIds] returns 0 records

In our Mongoose model, we have a product referring to an article.
this is a piece of the schema:
const product = new Schema({
article_id: Schema.Types.ObjectId,
title: String,
description: String,
...
In the API we are looking for products that are referring to a list of specific articles, and I wanted to use the $in operator:
const articles = ["5dcd2a95d7e2999332441825",
"5dcd2a95d7e2999332441827",
"5dcd2a96d7e2999332441829"]
filter.article_id = {
$in: articles.map(
article => new mongoose.Types.ObjectId(article)
),
};
return Product.find({ ...filter })
This returns 0 records, whereas I know for sure it should have returned at least 3. Looking at the console log, all that has happened is that the double quotes have been removed from the array during the ObjectId conversion.
Then I tried a different approach by returning {$oid: "id goes here"} for each mapped array item:
const articles = ["5dcd2a95d7e2999332441825",
"5dcd2a95d7e2999332441827",
"5dcd2a96d7e2999332441829"]
filter.article_id = {
$in: articles.map(
article => ({$oid: article})
),
};
return Product.find({ ...filter })
This gives a different array:
console.log(filter);
// {article_id: {$in: [{$oid: "5dcd2a95d7e2999332441825"}, {$oid: "5dcd2a95d7e2999332441827"}, {$oid: "5dcd2a96d7e2999332441829"}]}}
But in this case I get following error:
CastError: Cast to ObjectId failed for value "\"{$oid: \"5dcd2a95d7e2999332441825\"}\"".
Though - if I take that particular console logged filter and pass it in Studio 3T as a filter, I do indeed get the desired results.
Any idea what I doing wrong in this case?
Frick me! I am just a big idiot.. Apparently there was a .skip(10) added after the find() method -.-'.... Now I understand why 0 records where returned... Been spending hours on this..
For future references, Mongoose casts strings to ObjectIds automatically if defined in Schema. Therefor following is working exactly as it should given you don't skip the first 10 records:
const articles = ["5dcd2a95d7e2999332441825",
"5dcd2a95d7e2999332441827",
"5dcd2a96d7e2999332441829"]
filter.article_id = {
$in: articles
};
return Product.find({ ...filter }) // Note that I DON'T put .skip() here..

How to find the data inside of array using mongoose

I have a data like below in MongoDB.
const A = { uid: '1234',
works: [
{ name: 'car',
item:['tire','wheel']
},
{ name: 'ship',
item:['tire','wheel']
}
]
My goal is to find whether the name duplicated exists or not.
In conclusion, I want to get only the names.
So 'res.send(result)' gives me like '[car, ship]'.
But the code below doesn't work. How can I make that function? Thank you so much.
const workName = await User.findOne({
uid: userID, works:{$in:['name']}
});
The easy way is to find the aggregate of name and check if the count is greater than one. Since it is inside the the array we need to unwind it.
The below query works, to detect if a sub document contain duplicates for each document.
db.getCollection('collection_name').aggregate([{"$unwind":"$works"} ,{"$group":{"_id":{"name":"$works.name","uid":"$uid"},"count":{"$sum":1}}},{"$match":{"count":{"$gte":2}}}])
if you want to find in all the documents remove uid from _id of group.

Is it possible to populate nested references in Mongoose?

I'm new to MongoDB, trying to populate data from another collection into a response. The simplest example would be as follows:
const CartSchema = new Schema({
items: [{
product: { type: Schema.Types.ObjectId, ref: 'product' },
qty: Number
}],
...
});
I'm able to use .populate() when the relationships are at the root level, but in the above example, I have an array of items with their own properties, e.g. qty, plus an _id reference to a product. I would like to populate the product object into each car item, but can't seem to find any examples on what's the "right" way to do it.
Cart.findById(id)
.populate('products') // <-- something like this
.then(record => ... )
.catch(next);
I know that I could probably do a separate .find() on the products collection after locating the cart record and manually extend the initial object, but I was hoping there was a way to populate the data within the original query?
You can try this, it will work for you.
Cart.findById(id)
.populate('items.product')
.then(record => ... )
.catch(next);
.populate('items.product') will populate the product object of all the cart item present in the array.

Meteorjs - What is the proper way to join collections on backend

I am very new to meteor.js and try to build an application with it. This time I wanted to try it over MEAN stack but at this point I am struggled to understand how to join two collection on server side...
I want very identical behaviour like mongodb populate to fetch some properties of inner document.
Let me tell you about my collection it is something like this
{
name: 'Name',
lastName: 'LastName',
anotherObject: '_id of another object'
}
and another object has some fields
{
neededField1: 'asd',
neededField2: 'zxc',
notNeededField: 'qwe'
}
So whenever I made a REST call to retrieve the first object I want it contains only neededFields of inner object so I need join them at backend but I cannot find a proper way to do it.
So far while searching it I saw some packages here is the list
Meteor Collections Helper
Publish with Relations
Reactive joins in Meteor (article)
Joins in Meteor.js (article)
Meteor Publish Composite
You will find the reywood:publish-composite useful for "joining" related collections even though SQL-like joins are not really practical in Mongo and Meteor. What you'll end up with is the appropriate documents and fields from each collection.
Using myCollection and otherCollection as pseudonyms for your two collections:
Meteor.publishComposite('pseudoJoin', {
find: function() {
return myCollection.find();
},
children: [
{
find: function(doc) {
return otherCollection.find(
{ _id: post.anotherObject },
{ fields: { neededField1: 1, neededField2: 1 } });
}
}
]
});
Note that the _id field of the otherCollection will be included automatically even though it isn't in the list of fields.
Update based on comments
Since you're only looking to return data to a REST call you don't have to worry about cursors or reactivity.
var myArray = myCollection.find().fetch();
var myOtherObject = {};
var joinedArray = myArray.map(function(el){
myOtherObject = otherCollection.findOne({ _id: el.anotherObject });
return {
_id: el._id,
name: el.name,
lastName: el.lastName,
neededField1: myOtherObject.neededField1,
neededField2: myOtherObject.neededField2
}
});
console.log(joinedArray); // These should be the droids you're looking for
This is based on a 1:1 relation. If there are many related objects then you have to repeat the parent object to the number of children.

Building a dynamic mongo query for meteor

I'm building an app that has clickable 'filters'; I'm creating a list of objects(?) that I want to pass to a mongo 'find', so that I can pull out listings if selected attributes match a certain score.
My data is structured like this (a snippet):
name: 'Entry One',
location: {
type: 'Point',
coordinates: [-5.654182,50.045414]
},
dogs: {
score: '1',
when: 'seasonal',
desc: 'Dogs allowed from October to April'
},
lifeguard: {
score: '1',
when: 'seasonal',
desc: 'A lifeguard hut is manned between April and October',
times: ''
},
cafe: {
score: '1',
name:'Lovely cafe',
open:'seasonal'
}, ...
My search variable is a list of objects (I think?) that I assign to a session variable. If I output this session var ('searchString') via JSON.stringify, it looks like this:
{"cafe":{"score":"1"},"dogs":{"score":"1"}}
I'd like to pass this to my mongo find so that it only lists entries that match these scores on these attributes, but it's returning zero results. Do I need to somehow make this an $and query?
Currently it looks like this:
Beaches.find(searchString);
Unfortunately as soon as I drop searchString into the find, I get zero results even if it's empty {}. (When it's just a find() the entries list fine, so the data itself is ok)
What am I doing wrong? I'm relatively new to mongo/meteor, so I apologise in advance if it's something stupidly obvious!
Don't stringify the query. Flatten the object instead. Example:
Beaches.find({
"cafe.score": 1,
"dogs.score": 1,
});