首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用mongo选择单个记录中的数组

使用mongo选择单个记录中的数组
EN

Stack Overflow用户
提问于 2017-07-31 21:06:41
回答 1查看 146关注 0票数 0

我有一个文档,其中包含这样的数据:

代码语言:javascript
复制
{
    "data":"string"
    "arrayofdata" :[
        {},
        {},
        {}
    ]
}

我想要做的是只选择单个文档中的数据数组

我正在尝试获得这样的格式:

代码语言:javascript
复制
{ arrayofdata: [{},
                {},
                {}]}

我尝试的结果并不是很好:

代码语言:javascript
复制
[ { arrayofdata: {} },
  { arrayofdata: {} },
  { arrayofdata: {} } ]

你知道怎么解决这个问题吗?

这是我目前正在使用的:

代码语言:javascript
复制
async findSubElement(collection: string, subElementName: string, filter: {
    id?: number,
    offset?: number,
    limit?: number,
    order?: number,
    sort?: string,
    fields?: string[],
  }): Promise<any[]> {

    try {
      const aggregatePipeline: any = [];

      aggregatePipeline.push(
        {
          $unwind: '$' + subElementName,
        },
      );

      if (filter.sort) {
        filter.sort = subElementName + '.' + filter.sort;
      }

      // then we can apply filter on these documents
      aggregatePipeline.push(
        {
          $match: {
            _id: new ObjectID(filter.id),
          },
        },
        {
          $sort: {
            [filter.sort ? filter.sort : subElementName + '.created_at']: filter.order || 1,
          },
        },
        // Then, use the offset
        {
          $skip: filter.offset || 0,
        },
        // And the limit
        {
          $limit: filter.limit || 20,
        },
      );

      const fields: any = {};
      // If the user specified fields, build the 'fields' object in a Mongo way
      if (filter.fields && filter.fields.length > 0) {
        filter.fields.forEach(field => {
          fields[field] = '$' + subElementName + '.' + field;
        });
      } else {
        // If the user didn't specify any field, use a default value
        fields[subElementName] = 1;
      }
      fields['_id'] = false;

      // finally we "project" only the fields of our wanted subDocuments.
      aggregatePipeline.push({
        $project: fields,
      });

      const agg = await this.aggregate(
        collection,
        aggregatePipeline,
      );
      const result = await agg.toArray();

      return result.filter(a => a);
    } catch (error) {
      throw error;
    }
  }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-01 05:55:10

您需要去掉$unwind阶段,简单地使用$project,如下所示:

代码语言:javascript
复制
aggregatePipeline.push(
  {
    {
      $project:
      {
        "_id": 0 /* get rid of _id explicitly */,
        "arrayofdata": "$arrayofdata" /* only include arrayofdata field */
      }
    }
  }
);

关于你的评论:是的,你也可以使用一个标准的findOne()。实际上,您在代码中所做的所有工作都可以也应该在不使用聚合框架的情况下完成。请注意,只有当您的查询可以返回多个文档时,sort()skip()limit()才可用,因此对于findOne(),它们都不起作用。但是,它们都是使用findMany()工作的

您的$match会变成一个bog标准的过滤器(findOne的第一个参数),如下所示:

代码语言:javascript
复制
collection.findOne({_id: new ObjectID(filter.id)})

您的投影将成为findOne方法的$project参数:

代码语言:javascript
复制
// exclude "_id", include "arrayofdata"
collection.findOne({...}, {"_id": 0, "arrayofdata": 1})

$sort阶段变成一个.sort()命令:

代码语言:javascript
复制
// I'm not sure about the square brackets here but if your code works then this should work, too.
collection.findOne(...).sort([filter.sort ? filter.sort : subElementName + '.created_at']: filter.order || 1)

不过,要注意排序部分,并确保您理解这一点:How to project in MongoDB after sort?

$skip也是如此

代码语言:javascript
复制
collection.findOne(...).sort(...).skip(filter.offset || 0)

也适用于$limit

代码语言:javascript
复制
collection.findOne(...).sort(...).skip(...).limit(filter.limit || 20)

综上所述,下面是一个有效的查询,它可能在您的数据上下文中有意义,也可能没有意义,但它在语法上是正确的:

代码语言:javascript
复制
collection.find({_id: ObjectId("597fa64617a1cdcf9ace4712")}, {"_id": 0, "arrayofdata": 1}).sort({"arraydata":1}).skip(10).limit(20)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45416800

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档